⬅ 返回

1、法一 闫氏DP分析法

2、例题

3、代码

#include <iostream>
using namespace std;
const int N = 110;
int dp[N][N];
int v[N],w[N],s[N];
int n,m;
 
int main(){
    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=0;j<=m;j++)
        {
            dp[i][j]=dp[i-1][j];//选择i物品0件的状态转移
            for(int k=1;k<=s[i];k++)//从选择i物品1次开始遍历
            {
                if(k*v[i]<=j){
                    dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]*k]+w[i]*k);//更新
                }else{
                    break;
                }
                
            }
        }
    }
    cout<<dp[n][m]<<endl;
    
    
}

4、法二 将所有物品存储起来 看作01背包

4.1、二维 最大令N = 1e4 不推荐 空间不够

#include <iostream>
using namespace std;
const int N = 1e4;//最大
int n,m;
int dp[N][N];
int v[N],w[N],node=0;
 
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        while(c--)
        {
            ++node;
            v[node]=a;
            w[node]=b;
        }
    }
    for(int i=1;i<=node;i++)
    {
        for(int j=0;j<=m;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(v[i]<=j)
            {
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
            }
        }
    }
    cout<<dp[node][m]<<endl;
    
}

4.2、一维优化

#include <iostream>
using namespace std;
const int N = 1e6+10;
int v[N],w[N],dp[N],node=0;
 
int n,m;
 
int main(){
 
    cin>>n>>m;
    while(n--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        while(c--)
        {
            node++;
            v[node]=a;
            w[node]=b;
        }
    }
    for(int i=1;i<=node;i++)
    {
        for(int j=m;j>=v[i];j--)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }
    cout<<dp[m]<<endl;
    
    
}

4.3、当物品的数量很多时、可以进行二进制优化

思路

代码

#include <iostream>
using namespace std;
const int N = 1e5+10;
int v[N],w[N],dp[N];
int node=0;
int n,m;
 
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        int t=1;//t按照1 2 4 8 16 32 ........................
        while(t<c){
            node++;
            v[node]=a * t;//把t个i物品捆包起来
            w[node]=b * t;
            c=c-t;
            t=t*2;
        }
        if(c>0)//若不能刚好组合成2进制数,把剩余的捆包成一个物品
        {
            node++;
            v[node]=a * c;
            w[node]=b * c;
            
        }
    }
    
    //01背包
    ------------------------------------------------
    for(int i=1;i<=node;i++)
    {
        for(int j=m;j>=v[i];j--)
        {
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
    }
    -------------------------------------------------------------------
    cout<<dp[m]<<endl;
    
    
}