0-1揹包中每個物品重量和價值值都很小的情況
阿新 • • 發佈:2018-12-03
題目連結:http://hihocoder.com/problemset/problem/1364
描述
小Hi在遊樂園中獲得了M張獎券,這些獎券可以用來兌換獎品。
可供兌換的獎品一共有N件。第i件獎品需要Wi張獎券才能兌換到,其價值是Pi。
小Hi使用不超過M張獎券所能兌換到的最大獎品總價值是多少?
輸入
第一行兩個整數N,M。
接下來N行,每行兩個整數Wi,Pi。
對於 50%的資料: 1≤N,M≤1000
對於 100%的資料: 1≤N,M≤105,1≤Pi,Wi≤10。
輸出
一行一個整數,表示最大的價值。
樣例輸入3 10 2 3 8 8 10 10樣例輸出
11
解析:
典型的0-1揹包問題,但它的n和m很大,所以普通的O(n*m)的做法會超時。可以看到,此題與0-1揹包問題只有物品的重量和價值的資料量不一樣。那麼其實不同種類的物品最多隻有10*10種。每種有多少個可以計算,然後就變成了經典的多重揹包問題。。
code:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int dp[100010]; //重量為i時能得到的最大價值 void CompletePack(int weight, int value, int totWeight) { for(int j=weight; j<=totWeight; j++) dp[j] = max(dp[j],dp[j-weight]+value); } void ZeroOnePack(int weight, int value, int totWeight) { for(int j=totWeight; j>=weight; j--) dp[j] = max(dp[j],dp[j-weight]+value); } void MultiPack(int weight, int value, int totWeight, int num) {//重量,價值,總共不能超過的價值,數量 if(weight*num > totWeight) CompletePack(weight,value,totWeight); else { int k = 1; while(k < num) { ZeroOnePack(k*weight,k*value,totWeight); num -= k; k <<= 1; } ZeroOnePack(num*weight,num*value,totWeight); } } int main() { int n, m; while(~scanf("%d%d", &n,&m)) { memset(dp, 0, sizeof(dp)); int u, v, p[15][15] = {0}; for(int i=0; i<n; i++) { scanf("%d%d", &u,&v); //重量,價值 p[u][v]++; } for(int i=1; i<=10; i++) { for(int j=1; j<=10; j++) { MultiPack(i,j,m,p[i][j]); } } printf("%d\n", dp[m]); } return 0; }