2019-01-19 多重背包:每種東西有多個,因此可以把它拆分成多個01背包 優化:二進位拆分(拆成1+2+4+8+16+...,分別表示2的n次冪) 比如18=1+2+4+8+3,可以證明18以內的任何數都可以用這幾個數的和或差表示(每個數只能用一次)(0時則背包為空), 所以就把2個,4個.. ...
2019-01-19
多重背包:每種東西有多個,因此可以把它拆分成多個01背包
優化:二進位拆分(拆成1+2+4+8+16+...,分別表示2的n次冪)
比如18=1+2+4+8+3,可以證明18以內的任何數都可以用這幾個數的和或差表示(每個數只能用一次)(0時則背包為空),
所以就把2個,4個....綁定為一個物品,和一個一個的效果是一樣的
這樣就減少了拆分出來的物品的數量。(從n到log n)
代碼
1 #include<cstdio> 2 using namespace std; 3 const int maxn = 200005; 4 int n,m,a,b,c,cnt,ans,f[maxn],v[maxn],w[maxn]; 5 int main() { 6 scanf("%d%d",&n,&m); 7 for(int i = 1;i <= n;i++){ 8 scanf("%d%d%d",&a,&b,&c); 9 for(int j = 1;j <= c;j *= 2){ 10 c -= j; 11 v[++cnt] = a*j;//區分++cnt和cnt++ 12 w[cnt] = b*j; 13 } 14 if(c){ 15 v[++cnt] = a*c; 16 w[cnt] = b*c; 17 } 18 } 19 for(int i = 1;i <= cnt;i++) 20 for(int j = m;j >= w[i];j--){ 21 f[j] = max(f[j],f[j-w[i]]+v[i]); 22 ans = max(f[j],ans); 23 } 24 printf("%d",ans); 25 return 0; 26 }