hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(二进制优化 多重背包)
2014-02-20 15:03
316 查看
http://acm.hdu.edu.cn/showproblem.php?pid=2191
多重背包。每种物品的数量有限。求背包所放物品的最大价值。本题没要求钱正好花完,所以初始化时全部初始化为0。
另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为Σn[i]的01背包问题,直接求解,复杂度仍然是O(V*Σn[i])。
但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,每件物品只有一个。使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。另外,取超过n[i]件的策略必不能出现。
方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为 1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种 物品分成系数分别为1,2,4,6的四件物品。
分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。
这样就将第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为<math>O(V*Σlog n[i])的01背包问题,是很大的改进。
多重背包。每种物品的数量有限。求背包所放物品的最大价值。本题没要求钱正好花完,所以初始化时全部初始化为0。
另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为Σn[i]的01背包问题,直接求解,复杂度仍然是O(V*Σn[i])。
但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,每件物品只有一个。使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。另外,取超过n[i]件的策略必不能出现。
方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为 1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种 物品分成系数分别为1,2,4,6的四件物品。
分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。
这样就将第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为<math>O(V*Σlog n[i])的01背包问题,是很大的改进。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; int n,m; int c[110],w[110],num[110],dp[110]; void ZeroOnePack(int cost, int weight) { for(int i = n; i >= cost; i--) dp[i] = max(dp[i],dp[i-cost]+weight); } void CompletePack(int cost, int weight) { for(int i = cost; i <= n; i++) dp[i] = max(dp[i],dp[i-cost]+weight); } void MultiplePack(int cost, int weight, int amount) { if(cost * amount >= n)//如果当前物品的花费*数量 >= 背包总容量,可以看成当前物品是无限的,完全背包解决 { CompletePack(cost,weight); } else//否则,拆分该物品,变为01背包解决 { int k = 1; while(k < amount) { ZeroOnePack(k*cost,k*weight); amount -= k; k = k << 1; } ZeroOnePack(amount*cost,amount*weight); } } int main() { int test; scanf("%d",&test); while(test--) { scanf("%d %d",&n,&m); for(int i = 1; i <= m; i++) { scanf("%d %d %d",&c[i],&w[i],&num[i]); } memset(dp,0,sizeof(dp)); //dp[0] = 0; for(int i = 1; i <= m; i++) { MultiplePack(c[i],w[i],num[i]); } printf("%d\n",dp ); } return 0; }
相关文章推荐
- HDU - 2191 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (二进制优化多重背包)
- HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化)
- 多重背包问题:悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(HDU 2191)(二进制优化)
- [HDOJ] 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 [多重背包+二进制优化]
- 【多重背包】HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
- 多重背包—C - HDU 2191 - 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活
- 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包问题)2191 HDU
- HDU--杭电--2191--悼念512汶川大地震遇难同胞——珍惜现在,感恩生活--背包
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (多重背包 水)
- 【HDU 2191】 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- HDU 2191 - 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活(多重背包)
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (背包问题)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 动态规划多重背包
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (多重背包模板)
- HDU 2191 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 多重背包
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 多重背包
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活( 多重背包 )