当前位置:   article > 正文

动态规划之完全背包模型

动态规划之完全背包模型

前置知识:

01背包问题:动态规划之01背包模型_如何何何的博客-CSDN博客

完全背包问题:

给定一个有一定容量的背包,和 n 个物品,每个物品有无限件;

每个物品有其对应的体积和价值;

问背包最多能装下的物品的最大价值为多少。

输入格式:

第一行两个整数,N,V,分别表示物品数量和背包容积;

接下来有 N 行,每行两个整数 vi , wi 用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式:

输出一个整数,表示最大价值。

思路:

同01背包一样推导,面对第i件物品时,我们可以选0件、选1件、选2件……,那么方程就为:

f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i] + w[i], f[i - 1][j - 2 * v[i] + 2 * w[i] ......)。

如果这样做的话,就需要加上一层循环来决定选几件物品;

发现:

f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i], f[i - 1][j - 3 * v[i]] + 2 * w[i]......)

将 f[i][j-v[i]] 加上 w[i] 之后,就可以替换掉 f[i][j] 方程中选择1件,2件,3件……的所有情况;

所以dp方程优化为:

f[i][j] = max(f[i - 1][j],f[i][j - v[i]] + w[i])。

代码模板如下:

  1. #include<iostream>
  2. using namespace std;
  3. const int N=1010;
  4. int n,V;
  5. int f[N][N];
  6. int main(){
  7. cin>>n>>V;
  8. int v,w;
  9. for(int i=1;i<=n;i++){
  10. cin>>v>>w;
  11. for(int j=0;j<=V;j++){
  12. f[i][j]=f[i-1][j];
  13. if(j>=v)f[i][j]=max(f[i][j],f[i][j-v]+w);
  14. }
  15. }
  16. cout<<f[n][V];
  17. return 0;
  18. }

优化至一维:

和01背包不同,在完全背包中,状态是由本层的左边更新而来的,所以我们应该先把本层左边的状态先更新,所以是从前往后更新的。

代码如下:

  1. #include<iostream>
  2. using namespace std;
  3. const int N = 1010;
  4. int n, V;
  5. int f[N];
  6. int main() {
  7. cin >> n >> V;
  8. int v, w;
  9. for (int i = 1; i <= n; i++) {
  10. cin >> v >> w;
  11. for (int j = v; j <= V; j++) {
  12. f[j] = max(f[j], f[j - v] + w);//小于v的默认为上一层的状态
  13. }
  14. }
  15. cout << f[V];
  16. return 0;
  17. }

例题1 . 买书:

买书 - C语言网 (dotcpp.com)

思路:

求方案数,f[i][j] 表示只看前 i 件物品,钱数为 j 的时候的方案数。

买:f[i][j] = f[i][j-v] ;

不买:f[i][j] = f[i-1][j];

f[i][j]等于两者之和;

注意要初始化f[0][0]=1。

AC代码如下:

  1. //二维
  2. #include<iostream>
  3. using namespace std;
  4. const int N = 1010;
  5. int f[N][N];
  6. int m[] = { 0,10,20,50,100 };//书的下标从1开始
  7. int n;//钱
  8. int main() {
  9. cin >> n;
  10. f[0][0] = 1;
  11. for (int i = 1; i <= 4; i++)
  12. for (int j = 0; j <= n; j++) {
  13. f[i][j] += f[i - 1][j];//不买
  14. if (j >= m[i])f[i][j] += f[i][j - m[i]];//买
  15. }
  16. cout << f[4][n];
  17. return 0;
  18. }
  19. //一维
  20. #include<iostream>
  21. using namespace std;
  22. const int N = 1010;
  23. int f[N];
  24. int m[] = { 0,10,20,50,100 };//书的下标从1开始
  25. int n;//钱
  26. int main() {
  27. cin >> n;
  28. f[0] = 1;
  29. for (int i = 1; i <= 4; i++)
  30. for (int j = m[i]; j <= n; j++)
  31. f[j] += f[j - m[i]];//买
  32. cout << f[n];
  33. return 0;
  34. }

例题2 . 货币系统:

信息学奥赛一本通T1273-货币系统 - C语言网 (dotcpp.com)

思路:

和上题一样,有n个物品,每个物品无限个,有价值和体积属性,求恰好组成体积为 m 的方案数有多少;

f[i][j] 表示方案数;

f[i][j] 等于选当前货币和不选当前货币的方案数之和。

AC代码如下:

  1. //二维
  2. #include<iostream>
  3. using namespace std;
  4. const int N = 3010, M = 20;
  5. long long f[M][N];
  6. int n, m;//货币种类和目标值
  7. int main() {
  8. cin >> n >> m;
  9. int k;
  10. f[0][0] = 1;//注意要初始化
  11. for (int i = 1; i <= n; i++) {
  12. cin >> k;
  13. for (int j = 0; j <= m; j++) {
  14. f[i][j] += f[i - 1][j];//不选
  15. if (j >= k)f[i][j] += f[i][j - k];//选
  16. }
  17. }
  18. cout << f[n][m];
  19. return 0;
  20. }
  21. //一维
  22. #include<iostream>
  23. using namespace std;
  24. const int N = 3010;
  25. long long f[N];
  26. int n, m;//货币种类和目标值
  27. int main() {
  28. cin >> n >> m;
  29. int k;
  30. f[0] = 1;//注意要初始化
  31. for (int i = 1; i <= n; i++) {
  32. cin >> k;
  33. for (int j = k; j <= m; j++)
  34. f[j] += f[j - k];
  35. }
  36. cout << f[m];
  37. return 0;
  38. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/833609
推荐阅读
相关标签
  

闽ICP备14008679号