珍惜現在,感恩生活(九度教程第 103 題)

珍惜現在,感恩生活(九度教程第 103 題)

時間限制:1 秒 內存限制:32 兆 特殊判題:否

1.題目描述:

爲了挽救災區同胞的生命,心繫災區同胞的你準備自己採購一些糧食支援災
區,現在假設你一共有資金 n 元,而市場有 m 種大米,每種大米都是袋裝產品,
其價格不等,並且只能整袋購買。請問:你用有限的資金最多能採購多少公斤糧
食呢?
輸入:
輸入數據首先包含一個正整數 C,表示有 C 組測試用例,每組測試用例的第
一行是兩個整數 n 和 m(1<=n<=100, 1<=m<=100),分別表示經費的金額和大米的
種 類 , 然 後 是 m 行 數 據 , 每 行 包 含 3 個 數 p , h 和
c(1<=p<=20,1<=h<=200,1<=c<=20),分別表示每袋的價格、每袋的重量以及對應
種類大米的袋數。
輸出:
對於每組測試數據,請輸出能夠購買大米的最多重量,你可以假設經費買不
光所有的大米,並且經費你可以不用完。每個實例的輸出佔一行。
樣例輸入:
1
8 2
2 100 4
4 100 2
樣例輸出:
400

2.基本思路

我們可以將該問題轉化爲0-1揹包問題,其時間複雜度爲O(ci=1nki)O(c*\sum\limits_{i=1}^nk_i).當然該辦法已經可以解決問題,但但對於k的規模較大的情況下可以採用更好的發來來進行優化。這個就得聯繫到之前涉及到的二進制拆解。舉個例子,對於k=7,其實我們沒有必要把這個對象存儲7次,反之只需要存儲1,2,4這三種組合便可以組合出1~7之間的任意情況了。因此對於更一般的情況k,可以將其拆解爲1,2,4,...,k2c+11,2,4,...,k-2^c+1,其中c=log2kc=\lfloor \log_2^k\rfloor,通過此番拆解我們可以將算法的時間複雜度降到O(ci=1nlog2(ki))O(c*\sum\limits_{i=1}^nlog_2(k_i)).

3.代碼實現

#include <iostream>
#include <math.h>
#define M 2001
#define N 101
using namespace std;

struct rice{
    int price;
    int weight;
};
int IntPow(int x,int y){
    int ans=1;
    for(int i=1;i<=y;i++){
        ans*=x;
    }
    return ans;
}
int max(int a,int b){return a>b?a:b;}
int dp[N];
rice list[M];
int main()
{
    int C;
    scanf("%d",&C);
    int n,m;
    int cnt=1;
    for(int Case=1;Case<=C;Case++){
        cnt=1;
        scanf("%d%d",&n,&m);
        int p,h,c;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&p,&h,&c);
            int bound=int(log(c)/log(2));
            for(int j=0;j<bound;j++){
                list[cnt].price=IntPow(2,j)*p;
                list[cnt].weight=IntPow(2,j)*h;
                cnt++;
            }
            if(c-IntPow(2,bound)+1!=0){
                list[cnt].price=(c-IntPow(2,bound)+1)*p;
                list[cnt].weight=(c-IntPow(2,bound)+1)*h;
                cnt++;
            }
        }
//        for(int i=1;i<cnt;i++){
//            printf("price=%d,weight=%d\n",list[i].price,list[i].weight);
//        }
        for(int i=0;i<cnt;i++)dp[i]=0;//初始化
        for(int i=1;i<cnt;i++){
            for(int j=n;j>=list[i].price;j--){
                dp[j]=max(dp[j],dp[j-list[i].price]+list[i].weight);
            }
        }
        printf("%d\n",dp[n]);

    }
    return 0;
}
/*
1
8 2
2 100 4
4 100 2
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章