当前位置:   article > 正文

【动态规划】—— 背包模型_完全背包求方案数模板

完全背包求方案数模板


回顾一下 01 背包问题 (每个物品只能选一次)

集合划分的依据:用“最后一步”来划分 


 完全背包问题:每个物品可以选 0,1,2,3... 个


 通过比较可以得到:

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


背包问题的注意事项 

  1. 当空间优化到1维之后,只有完全背包问题的体积是从小到大循环       
  2. for 物品
        for 体积
            for 决策

AcWing 6. 多重背包问题 III 


 


  1. #include <cstring>
  2. #include <iostream>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 20010;
  6. int n, m;
  7. int f[N], g[N], q[N];
  8. int main()
  9. {
  10. cin >> n >> m;
  11. for (int i = 0; i < n; i ++ )
  12. {
  13. int v, w, s;
  14. cin >> v >> w >> s;
  15. memcpy(g, f, sizeof f);
  16. for (int j = 0; j < v; j ++ )
  17. {
  18. int hh = 0, tt = -1;
  19. for (int k = j; k <= m; k += v)
  20. {
  21. if (hh <= tt && q[hh] < k - s * v) hh ++ ;
  22. while (hh <= tt && g[q[tt]] - (q[tt] - j) / v * w <= g[k] - (k - j) / v * w) tt -- ;
  23. q[ ++ tt] = k;
  24. f[k] = g[q[hh]] + (k - q[hh]) / v * w;
  25. }
  26. }
  27. }
  28. cout << f[m] << endl;
  29. return 0;
  30. }

AcWing 423. 采药 

  1. 70 3
  2. 71 100
  3. 69 1
  4. 1 2

输出样例:

3

这是01背包问题的简单应用 

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

AcWing 1024. 装箱问题 

输入样例:

  1. 24
  2. 6
  3. 8
  4. 3
  5. 12
  6. 7
  7. 9
  8. 7

输出样例:

0

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

AcWing 1022. 宠物小精灵之收服 

 

输入样例1:

  1. 10 100 5
  2. 7 10
  3. 2 40
  4. 2 50
  5. 1 20
  6. 4 20

输出样例1:

3 30

输入样例2:

  1. 10 100 5
  2. 8 110
  3. 12 10
  4. 20 10
  5. 5 200
  6. 1 110

输出样例2:

0 100

  1. 花费1:精灵球的数量
  2. 花费2:皮卡丘的体力值
  3. 价值:小精灵的数量

状态计算:

f[i,j,k]=max(f[i-1,j,k],f[i-1,j-v1[i],k-v2[i]]+1)

最多收服的小精灵数量:f[K,N,K]

最小消耗的体力:f[K,N,m]==f[K,N,M]


  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N = 1010, M = 510;
  5. int n, V1, V2;
  6. int f[N][M];
  7. int main()
  8. {
  9. cin >> V1 >> V2 >> n;
  10. for(int i = 0; i < n; i ++ )
  11. {
  12. int v1, v2;
  13. cin >> v1 >> v2;
  14. for(int j = V1; j >= v1; j -- )
  15. for(int k = V2; k >= v2; k --)
  16. f[j][k] = max(f[j][k], f[j - v1][k - v2] + 1);
  17. }
  18. cout << f[V1][V2 - 1] << ' ';
  19. int k = V2 - 1;
  20. while(k > 0 && f[V1][k - 1] == f[V1][V2 - 1]) k --;
  21. cout << V2 - k << endl;
  22. return 0;
  23. }

AcWing 8. 二维费用的背包问题 

输入样例

  1. 4 5 6
  2. 1 2 3
  3. 2 4 4
  4. 3 4 5
  5. 4 5 6

输出样例:

8


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

AcWing 1020. 潜水员 

输入样例:

  1. 5 60
  2. 5
  3. 3 36 120
  4. 10 25 129
  5. 5 50 250
  6. 1 45 130
  7. 4 20 119

输出样例:

249

  1. #include <cstring>
  2. #include <iostream>
  3. using namespace std;
  4. const int N = 22, M = 80;
  5. int n, m, K;
  6. int f[N][M];
  7. int main()
  8. {
  9. cin >> n >> m >> K;
  10. memset(f, 0x3f, sizeof f);
  11. f[0][0] = 0;
  12. while (K -- )
  13. {
  14. int v1, v2, w;
  15. cin >> v1 >> v2 >> w;
  16. for (int i = n; i >= 0; i -- )
  17. for (int j = m; j >= 0; j -- )
  18. f[i][j] = min(f[i][j], f[max(0, i - v1)][max(0, j - v2)] + w);
  19. }
  20. cout << f[n][m] << endl;
  21. return 0;
  22. }

 AcWing 278. 数字组合

输入样例:

  1. 4 4
  2. 1 1 2 2

输出样例:

3

M 看成是背包容量

每个数看成是一个物品,Ai 看成是体积

目标:求出总体积恰好是 M 的方案数 


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

AcWing 1019. 庆功会 

输入样例:

  1. 5 1000
  2. 80 20 4
  3. 40 50 9
  4. 30 50 7
  5. 40 30 6
  6. 20 20 1

输出样例:

1040

多重背包问题的模板题 

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

AcWing 1023. 买书 

 

输入样例1:

20

输出样例1:

2

输入样例2:

15

输出样例2:

0

输入样例3:

0

输出样例3:

1

 

f[i,j]=f[i-1,j]+f[i,j-v]


二维DP的朴素写法

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

优化后的一维DP解法 

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

AcWing 12. 背包问题求具体方案

输入样例

  1. 4 5
  2. 1 2
  3. 2 4
  4. 3 4
  5. 4 6

输出样例:

1 4

01背包问题的思路如下

其实是判断出每个物体是否被选

动态规划问题 -> 最短路问题(求路径问题)


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

AcWing 1013. 机器分配

 

输入样例:

  1. 3 3
  2. 30 40 50
  3. 20 30 50
  4. 20 25 30

输出样例:

  1. 70
  2. 1 1
  3. 2 1
  4. 3 1

这道题的本质上是一个分组背包问题+背包问题求具体方案

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N = 11, M = 16;
  5. int n, m;
  6. int w[N][M];
  7. int f[N][M];
  8. int way[N];
  9. int main()
  10. {
  11. cin >> n >> m;
  12. for (int i = 1; i <= n; i ++ )
  13. for (int j = 1; j <= m; j ++ )
  14. cin >> w[i][j];
  15. for (int i = 1; i <= n; i ++ )
  16. for (int j = 0; j <= m; j ++ )
  17. for (int k = 0; k <= j; k ++ )
  18. f[i][j] = max(f[i][j], f[i - 1][j - k] + w[i][k]);
  19. cout << f[n][m] << endl;
  20. int j = m;
  21. for (int i = n; i; i -- )
  22. for (int k = 0; k <= j; k ++ )
  23. if (f[i][j] == f[i - 1][j - k] + w[i][k])
  24. {
  25. way[i] = k;
  26. j -= k;
  27. break;
  28. }
  29. for (int i = 1; i <= n; i ++ ) cout << i << ' ' << way[i] << endl;
  30. return 0;
  31. }

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

闽ICP备14008679号