背包问题(01背包、完全背包、部分背包)
之前写过一篇博客,这次看了下背包九讲,主要看的是部分背包的优化解法,转化的很巧妙,时间复杂度可以达到O(n*∑log(amount[i])*V),就是把原先每个背包的数量分成一堆一堆的。
例如,假如物品i有14件,那么我们可以将它转化成若干个01背包问题,这几个子问题的背包价值和代价为1*price,1*cost,2*price,2*cost,4*price,4*cost, 7*price, 7*cost,这样我们总可以将1-13之内的数用这几个数来表示,一般的对于一个amout,我们只需要找到最大k,使得amout-2^(k+1) > 0. 这种优化方法,可以简单的这么理解,就是对于每一个新的子01背包,我们要么选它要么不选它,dp[w]中记录的总是满足条件的最大价值,这样我们总能遍历到任何一个1-13内的状态,使得dp[w]达到最大。
代码如下:
#include <iostream> using namespace std; const int m = 100; const int INF = -1000; int dp[m]; int maxn(int a, int b) { return a > b ? a : b; } /* 如果要求正好装满,则初始化未INF,否则初始化未0 */ void init() { for(int k = 0; k <= 100; k++) dp[k] = INF; // dp[0]=0; } int zeroOnePack(int price, int cost, int W) { for(int w = W; w >= 1; --w) { if(w >= cost) dp[w] = maxn(price + dp[w - cost], dp[w]); } return dp[W]; } int CompletePack(int price, int cost, int W) { for(int w = 1; w <= W; ++w) { if(w >= cost) dp[w] = maxn(price+dp[w-cost], dp[w]); } return dp[W]; } int multiPack(int price, int cost, int amount, int W) { if(amount*cost >= W) CompletePack(price, cost, W); else { int k = 1; while(k < amount) { zeroOnePack(k*price, k*cost, W); amount -= k; k *= 2; } zeroOnePack(amount*price, amount*cost, W); } cout<<dp[W]<<endl; return dp[W]; } int main() { int price[5] = {1,2,3}; int cost[5] = {5,2,4}; int amount[5] = {2,2,2}; init(); for(int i = 0; i < 3; ++i) multiPack(price[i], cost[i], amount[i], 5); return 0; }
posted on 2012-10-10 16:18 buptLizer 阅读(2980) 评论(0) 编辑 收藏 举报