特点:01背包同一物品只能取一次,完全背包同一物品可以取多次

题目描述:

方法1:二维dp

与01背包不同点:

  • dp数组第一行初始化时不同

  • 递推时,放物品i时处理情况不同,dp[i - 1][j - weight[i]] + value[i]变为dp[i][j - weight[i]] + value[i]

  • 01背包由正上方与左上方推出,完全背包由正上方与同行左方推出

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int solve(int N,int V,vector<int> weight,vector<int> value){
    vector<vector<int>>dp(N,vector<int>(V+1,0));
    for(int i=weight[0];i<=V;i++) dp[0][i] = (i / weight[0]) * value[0];//初始化dp数组
    
    for(int i=1;i<N;i++){
        for(int j=1;j<=V;j++){//更新dp数组
            if(j<weight[i]) dp[i][j] = dp[i-1][j];//装不下
            else dp[i][j] = max(dp[i-1][j] , dp[i][j-weight[i]] + value[i]);//装得下
        }
    }
    return dp[N-1][V];
}

int main(){
    int N,V;
    cin>>N>>V;
    vector<int>weight(N,0);
    vector<int>value(N,0);
    for(int i=0;i<N;i++){
        cin>>weight[i];
        cin>>value[i];
    }
    
    int max_value = solve(N,V,weight,value);
    cout<<max_value<<endl;
    return 0;
}

方法2:一维dp

与01背包不同点:

  • 因为01背包由正上方与左上方推出,完全背包由正上方与同行左方推出,所以一维迭代时,01背包得由右向左,完全背包得由左向右

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int solve(int N,int V,vector<int> weight,vector<int> value){
    vector<int>dp(V+1,0);
    for(int i=weight[0];i<=V;i++) dp[i] = (i / weight[0]) * value[0];//初始化dp数组
    
    for(int i=1;i<N;i++){
        for(int j=weight[i];j<=V;j++){//更新dp数组
            dp[j] = max(dp[j] , dp[j-weight[i]] + value[i]);//装得下
        }
    }
    return dp[V];
}

int main(){
    int N,V;
    cin>>N>>V;
    vector<int>weight(N,0);
    vector<int>value(N,0);
    for(int i=0;i<N;i++){
        cin>>weight[i];
        cin>>value[i];
    }
    
    int max_value = solve(N,V,weight,value);
    cout<<max_value<<endl;
    return 0;
}
  • 一维dp时,装不下就不需要更新dp数组了