01 背包问题

1 表示使用 1 次或者使用 0 次
image.png
DP分析法

  • 状态表示 f[i][j]
    • 集合:所有数量为 i ,总体积不超通过 j 的物品的选法集合,不能重复选择物品
    • 属性:最大价值
  • 状态计算
    • 所有不选择第 i 个物品方案中的最大值 f[i-1][j]
    • 所有选择第 i 个物品方案中的最大值 f[i-1][j-v[i]]+w[i]

朴素代码

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

优化空间后代码

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

优化思路

由于j是从大到小循环的,假设j = 5; j >= 2; j –; 也就是这一层(第i层)会先算出来f[5],(注意这个时候,第i层正在算f[5], 也就是说第i层没有更新f[4] f[3],也就是此时的f[4] f[3] 是i - 1层的)那么算f[5]要用到比他更小的f[4]或者f[3]也就是i - 1层的了。

完全背包问题

image.png

DP分析法

  • 状态表示 f[i][j]
    • 集合:所有数量为i,总体积不超过j的物品的选法集合,能重复选择物品
    • 属性:最大价值
  • 状态计算
    • 不选第i个物品 f[i-1][j]
    • 所有选i个物品最大值 f[i][j-v]+w

推导方式
image.png
朴素代码

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

优化后代码

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