0-1背包

每种物品只有一个,物品i的体积:w[i]、价值:v[i]

dp[i][j]:前i个物品装进容量为j的背包所获得的最大价值

  • ① 不放第i个物品 dp[i][j]=dp[i-1][j]
  • ② 放入第i个物品 dp[i][j]=dp[i-1][j-w[i]]+v[i]
#include<iostream>
using namespace std;
const int maxn=1001;
int w[maxn];
int v[maxn];
int dp[maxn][maxn];

int best(int sum,int n){
    for(int i=0;i<=n;i++){//初始化
        dp[i][0]=0;
    }
    for(int i=0;i<=sum;i++){
        dp[0][i]=0;
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=sum;j++){
            if(w[i]>j)dp[i][j]=dp[i-1][j];
            else dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    return dp[n][sum];
}


int main(){
    int sum,n;
    while(scanf("%d%d",&sum,&n)!=EOF){
        for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);//注意从1开始放,0留作边界
        printf("%d\n",best(sum,n));
    }
}

优化:压缩空间

  • dp[i][j]每行只取决于上一行前面部分的值
  • 故从后往前更新
#include<iostream>
using namespace std;
const int maxn=1001;
int w[maxn];
int v[maxn];
int dp[maxn];//只保存一行状态(容量:0~sum)

int best(int sum,int n){
    
    for(int i=0;i<=sum;i++){//初始化
        dp[i]=0;
    }
    
    for(int i=1;i<=n;i++){
        for(int j=sum;j>=w[i];j--){//从后往前更新
             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    return dp[sum];
}


int main(){
    int sum,n;
    while(scanf("%d%d",&sum,&n)!=EOF){
        for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);//注意从1开始放,0留作边界
        printf("%d\n",best(sum,n));
    }
}