0-1 背包问题

Acwing
image.png

朴素做法

状态转移方程:
定义背包九讲 - 图2:前i个物品,背包容量j下的最优解

  • 当前背包容量不够背包九讲 - 图3 为前 i-1 个物品最优解: 背包九讲 - 图4
  • 当前背包容量够,判断选与不选第i个物品

选:背包九讲 - 图5
不选:背包九讲 - 图6

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N =1010;
  5. int f[N][N];
  6. int w[N],v[N]; // 价值 容量
  7. int main(){
  8. int m,n;
  9. cin >> n >>m ;
  10. for(int i=1;i<=n;i++){
  11. cin >> v[i] >>w[i];
  12. }
  13. for(int i=1;i<=n;i++) // 每个物体 涉及到i-1 从1开始
  14. for(int j=1;j<=m;j++){ // 每个容量 涉及到i-1 从1开始
  15. if(j<v[i]) f[i][j] = f[i-1][j];
  16. else
  17. f[i][j]=max(f[i-1][j],(f[i-1][j-v[i]])+w[i]); //
  18. }
  19. cout << f[n][m];
  20. return 0;
  21. }

空间优化

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N =1010;
  5. int f[N];
  6. int w[N],v[N]; // 价值 容量
  7. int main(){
  8. int m,n;
  9. cin >> n >>m ;
  10. for(int i=1;i<=n;i++){
  11. cin >> v[i] >>w[i];
  12. }
  13. for(int i=1;i<=n;i++) // 每个物体 涉及到i-1 从1开始
  14. for(int j=m;j>=v[i];j--){ // 每个容量 涉及到i-1 从1开始
  15. f[j]=max(f[j],(f[j-v[i]])+w[i]); //
  16. }
  17. cout << f[m];
  18. return 0;
  19. }

完全背包问题

Acwing
image.png
image.png
详解

朴素做法

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int dp[N][N];
int v[N],w[N]; // 体积,价值
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>> v[i] >> w[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=0;k*v[i]<=j;k++){
                dp[i][j]= max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]); // 状态转移方程
            }
        }
    }
    cout << dp[n][m];
    return 0;
}

时间复杂度优化

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int dp[N][N];
int v[N],w[N]; // 体积,价值
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>> v[i] >> w[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(j<v[i])  dp[i][j]=dp[i-1][j];
            else
                dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
        }
    }
    cout << dp[n][m];
    return 0;
}

空间优化最终版

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int dp[N];
int v[N],w[N]; // 体积,价值
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>> v[i] >> w[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=v[i];j<=m;j++){  // 对应的01背包是 for(int j=m;j>=v[i];j--)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]); 
        }
    }
    cout << dp[m];
    return 0;
}

多重背包问题

image.png

朴素做法

#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int dp[N];
int v[N],w[N],s[N]; // 体积  价值  个数
int main(){
    int  n ,m ;
    cin >> n >> m;
    for(int i =1;i<=n;i++){
        cin >> v[i]>> w[i]>> s[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=m;j>=v[i];j--){
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
                dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout << dp[m];
    return 0;
}

二进制优化

acwing

#include<iostream>
#include<algorithm>

using namespace std;
const int N=1010;
int dp[2001];
int v[N],w[N],s[N];// 体积 价值
const int M=15000; // 1000* lg2000
int a[M],b[M]; // 体积 价值
int main(){
    int n,m;
    cin>> n>>m;
    for(int i=1;i<=n;i++){
        cin>> v[i]>>w[i]>>s[i];
    }
    int cnt=1;
    // 对每个物体进行重组
    for(int i=1;i<=n;i++){
        for(int j=1;j<s[i];j*=2){
            s[i]-=j;
            a[cnt]=v[i]*j;
            b[cnt++]=w[i]*j;
        }
        if(s[i]>0){
            a[cnt]=v[i]*s[i];
            b[cnt++]=w[i]*s[i];
        }
    }
    //01背包
    for(int i=1;i<=cnt;i++) // 注意此时的个数变成了cnt
        for(int j=m;j>=a[i];j--){
            dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
        }
        cout << dp[m];
    return 0;
}

分组背包问题

image.png

状态的划分:
选这组的第i个物品
image.png

#include <iostream>
#include<algorithm>
using namespace std;
const int N=102;
int dp[N];
int v[N][N],w[N][N],s[N]; // 第i组第j个物品的体积,价值;   每组的个数

int main(){
    int n,m;
    cin >> n>> m; // 组数   背包体积
    for(int i=1;i<=n;i++){
        cin >> s[i];
        for(int j=1;j<=s[i];j++)
            cin>>v[i][j] >> w[i][j];    
    }

    for(int i=1;i<=n;i++){
        for(int j=m;j>=1;j--){
            for(int k=1;k<=s[i];k++){
                if(j>=v[i][k])
                    dp[j] =max(dp[j],dp[j-v[i][k]]+w[i][k]);
            }
        }
    }
    cout << dp[m];
    return 0;
}