动态规划初步-完全背包问题

转载自:https://blog.csdn.net/stack_queue/article/details/52925489

问题描述:

有n种重量和价值分别为wi,vi的物品。从这些物品中挑选总重量不超过m的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。

限制条件:

1<=n<=100

1<=wi,vi<=100

1<=w<=10000

思路分析:

与之前的01背包问题相似(01背包问题链接),只是这里每件物品可供挑选的数量不限,因此首先想到的就是,在先前01背包问题的基础上,对第i件物品的数量进行讨论。

即:dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}

这里的k为第i件物品的件数,即分别讨论拿0,1,2,3……件i物品,取其中的最大值作为dp[i][j]的值。

代码实现上很容易想到加一层for循环。


  
  
  1. int DP()
  2. {
  3. for( int i= 1;i<=n;i++)
  4. {
  5. for( int j= 1;j<=m;j++)
  6. {
  7. for( int k= 0;k*w[i]<=j;k++)
  8. {
  9. dp[i][j]=max(dp[i][j],dp[i -1][j-k*w[i]]+k*v[i]);
  10. }
  11. }
  12. }
  13. return dp[n][m];
  14. }

可是这样的程序构成了3层循环,最内层循环的最坏情况可能从0循环至m,所以这个算法的时间复杂度为O(n*m^2)。这样并不够好。

注意到dp[i][j]中计算k个的情况与在dp[i][j-w[i]]中计算k-1个一样,也就是进行了很多重复计算,从这个角度去寻找优化的方法。

dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}

=max(dp[i-1][j],max{dp[i-1][j-k*w[i]]+k*v[i] | k>=1})

=max(dp[i-1][j],max{dp[i-1][j-w[i]-k*w[i]]+k*v[i] | k>=0})//此处与第一行结构相同

=max(dp[i-1][j],dp[i][j-w[i]])

这样一来就不需要关于k的for循环了,便可以用O(n*m)时间解决问题。

代码实现:


  
  
  1. #include"cstdio"
  2. #include"algorithm"
  3. using namespace std;
  4. int n,m;
  5. int w[ 105],v[ 105];
  6. int dp[ 105][ 10005]={ 0};
  7. int DP()
  8. {
  9. for( int i= 1;i<=n;i++)
  10. {
  11. for( int j= 1;j<=m;j++)
  12. {
  13. /*
  14. for(int k=0;k*w[i]<=j;k++)
  15. {
  16. dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
  17. }
  18. */
  19. if(j<w[i])
  20. dp[i][j]=dp[i -1][j];
  21. else
  22. dp[i][j]=max(dp[i -1][j],dp[i][j-w[i]]+v[i]);
  23. }
  24. }
  25. return dp[n][m];
  26. }
  27. int main()
  28. {
  29. scanf( "%d%d",&n,&m);
  30. for( int i= 1;i<=n;i++)
  31. scanf( "%d%d",&w[i],&v[i]);
  32. printf( "%d\n",DP());
  33. return 0;
  34. }
  35. /*
  36. 测试样例:
  37. 3 7
  38. 3 4
  39. 4 5
  40. 2 3
  41. */









猜你喜欢

转载自blog.csdn.net/weixin_41969587/article/details/82505478
今日推荐