完全背包

今天药忘吃喽~ 2022-05-31 01:05 279阅读 0赞

问题:

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

这个问题非常类似于01背包问题,所 不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解 01背包时的思路,令f[i][j]表示前i种物品恰放入一个容量为c的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

f[i][j]=max{f[i-1][j-k*w[i]]+k*v[i]|0<=k*c[i]<=v}

这跟01背包问题一样有O(VN)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度可以认为是O(V*Σ(V/c[i])),是比较大的。

将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。

其中F[i-1][j-k*w[i]]+k*v[i]表示前i-1物品中选取若干件物品放入剩余空间为j-k*w[i]的背包中所能得到的最大价值加上k件第i物品的总价值;

设物品种数为n,背包容量为c,第i物品体积为w[i],第i物品价值为v[i]。

代码1:

  1. #include<queue>
  2. #include<stack>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<stdlib.h>
  6. #include<algorithm>
  7. using namespace std;
  8. int dp[1001][1001];
  9. int w[1001];
  10. int v[1001];
  11. int main()
  12. {
  13. int n,c;
  14. while(scanf("%d%d",&n,&c)!=EOF)
  15. {
  16. int i,j;
  17. memset(dp,0,sizeof(dp));
  18. for(i=1; i<=n; i++)
  19. scanf("%d",&w[i]);
  20. for(i=1; i<=n; i++)
  21. scanf("%d",&v[i]);
  22. for(i=1; i<=n; i++)
  23. {
  24. for(j=0; j<=c; j++)
  25. {
  26. for(int k=0; k*w[i]<=j; k++)
  27. dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);//表示前i-1种物品中选取若干件物品放入剩余空间为j-k*w[i]的背包中所能得到的最大价值加上k件第i种物品的总价值;
  28. }
  29. }
  30. printf("%d\n",dp[n][c]);
  31. }
  32. return 0;
  33. }

简单优化:筛选

  1. 这个筛选过程如下:先找出体积大于背包的物品直接筛掉一部分(也可能一种都筛不掉),然后筛选出同体积但价值大的物品,其余的都筛掉(这也可能一件都筛不掉)即若两件物品满足w\[i\] w\[j\]&&v\[i\] v\[j\]时将第j种物品直接筛选掉。因为第i种物品比第j种物品物美价廉,用i替换j得到至少不会更差的方案。

转化为01背包:

  1. 因为同种物品可以多次选取,那么第i种物品最多可以选取c/w\[i\]件价值不变的物品,然后就转化为01背包问题。整个过程的时间复杂度并未减少。

如果把第i种物品拆成体积为w[i]×2k价值v[i]×2k的物品,其中满足w[i]×2k≤V。那么在求状态F[i][j]时复杂度就变为O(log2(V/C[i]))。整个时间复杂度就

变为O(NVlog2(c/w[i]))

将原始算法的DP思想转变一下。

设F[i][j]表示出在前i种物品中选取若干件物品放入容量为j的背包所得的最大价值。那么对于第i种物品的出现,我们对第i种物品放不放入背包

进行决策。如果不放那么F[i][j]=F[i-1][j];如果确定放,背包中应该出现至少一件第i种物品,所以F[i][j]种至少应该出现一件第i种物品,

即F[i][j]=F[i][j-w[i]]+v[i]。为什么会是F[i][j-w[i]]+v[i]?因为我们前面已经最大限度的放了第i件物品,如果能放就放这最后的一件,

(或者理解为前面已经往背包中放入了第i件物品,我们每一次只增加一件的往背包里放,而且只能增加一件,多了放不下)

代码2:

  1. #include<stack>
  2. #include<queue>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<algorithm>
  6. using namespace std;
  7. int dp[1010][1010];
  8. int w[1010];
  9. int v[1010];
  10. int main()
  11. {
  12. int n,c;
  13. while(scanf("%d%d",&n,&c)!=EOF)
  14. {
  15. memset(dp,0,sizeof(dp));
  16. int i,j;
  17. for(i=1; i<=n; i++)
  18. scanf("%d",&w[i]);
  19. for(i=1; i<=n; i++)
  20. scanf("%d",&v[i]);
  21. for(i=1; i<=n; i++)
  22. {
  23. for(j=0; j<=c; j++)
  24. {
  25. if(j>=w[i])
  26. dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);//注意此处与0-1背包的不同,0-1背包:max(dp[i-1][j],dp[i-1][j-w[i]+v[i])
  27. else
  28. dp[i][j]=dp[i-1][j];
  29. }
  30. }
  31. printf("%d\n",dp[n][c]);
  32. }
  33. return 0;
  34. }

一维解法:

和01背包问题一样,完全背包也可以用一维数组来保存数据。算法样式和01背包的很相似,唯一不同的是对V遍历时变为正序,而01背包为逆序

。01背包中逆序是因为F[i][]只和F[i-1][]有关,且第i的物品加入不会对F[i-1][]状态造成影响。而完全背包则考虑的是第i物品的出现的问题,

第i种物品一旦出现它势必应该对第i种物品还没出现的各状态造成影响。也就是说,原来没有第i种物品的情况下可能有一个最优解,现在第i种物品

出现了,而它的加入有可能得到更优解,所以之前的状态需要进行改变,故需要正序。

代码:

  1. #include<stack>
  2. #include<queue>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<algorithm>
  6. using namespace std;
  7. int dp[1010];
  8. int w[1010];
  9. int v[1010];
  10. int main()
  11. {
  12. int n,c;
  13. while(scanf("%d%d",&n,&c)!=EOF)
  14. {
  15. int i,j,k;
  16. memset(dp,0,sizeof(dp));
  17. for(i=1;i<=n;i++)
  18. scanf("%d",&w[i]);
  19. for(i=1;i<=n;i++)
  20. scanf("%d",&v[i]);
  21. for(i=1;i<=n;i++)
  22. {
  23. for(j=w[i];j<=c;j++)//注意此处与0-1背包的不同,0-1为倒序(j=c;j>=w[i];j--)
  24. {
  25. dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
  26. }
  27. }
  28. printf("%d\n",dp[c]);
  29. }
  30. return 0;
  31. }

感谢大佬http://blog.csdn.net/howardemily/article/details/55223039

发表评论

表情:
评论列表 (有 0 条评论,279人围观)

还没有评论,来说两句吧...

相关阅读

    相关 背包DP | 完全背包问题

    > 完全背包问题:有n种物品,每一件的物品重量为 w\[ i \],价值为 c\[ i \]。现有一个容量为V的背包 (背包的最大承重为V),问如何选取物品放入背包,使得背包内

    相关 完全背包

    完全背包在背包九讲中有很详细的讲解,但是今天碰到题尝试了一下他给的算法,发现并不快,看了一下其他的代码,速度很快! 题目链接http://hihocoder.com/prob

    相关 完全背包问题

    1. 问题描述 有 N 种物品, 物品 i 的重量为 wi, 价格为 vi, 背包所能承受的最大重量为 W。 其中, N,W,wi,vi≥0 若每种物品仅有一件,

    相关 01背包,完全背包

    01背包问题:一个背包总容量为V,现在有N个物品,第i个 物品体积为weight\[i\],价值为value\[i\],现在往背包里面装东西,怎么装能使背包的内物品价值最大?

    相关 完全背包

    完全背包和01背包的区别 > 01背包:有n个物品,每种物品只能被使用一次 > > 完全背包:有n个物品,每个物品可以被多次使用 完全背包的递推公式可以由01背包的递推公

    相关 完全背包

    问题: 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c\[i\],价值是w\[i\]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量

    相关 0-1背包&完全背包

    First:0-1背包问题 1.定义define: 所谓的0-1背包就是指每种物品只有一件,而每件物品只有两种选择,即选择放或是不放 2.问题: 一个小偷来出来活动