背包问题

01 背包

这类题型每个物品只有一件,思路很简单,可以打表格理解

(1)不拿这个物品,价值就是拿上一件的价值 w[i][j]=w[i-1][j]
(2)拿这个物品,价值增加的同时可用体积减少 w[i][j]=w[i-1][j-v[i]]+c[i]

二维数组

i表示循环到第几件物品,j 表示已经使用了多少体积
初始值一件物品都不拿 w[0][0]=0

w[i][j] = max(w[i-1][j], w[i-1][j-v[i]] + c[i])

一维数组的优化

优化之后 j表示现在还剩多少体积,可以选择拿这一物品或者不拿,取两个选择的最大值

dp[j] = max(dp[j], dp[j - v[i]] + w[i])

这个循环是从后往前循环,找到自己体积停止

#include<bits/stdc++.h>
using namespace std;
int c[1005],v[1005],w[1000005];
int main()
{
    int n,V,i,j;
    cin>>n>>V;
    for(i=1;i<=n;i++)
    {
        cin>>v[i]>>c[i];
    }
    for(i=1;i<=n;i++)
    {
        for(j=V;j>=v[i];j--)
        {
            w[j]=max(w[j],w[j-v[i]]+c[i]);
        }
    }
    cout<<w[V];
    return 0;
}

完全背包

这类题型每个物品都有无数件

二维数组

f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i])

一维数组

f[j] = max(f[j],f[j-v[i]]+w[i])

这个和01背包的状态转移方程很相似,区别就在角标,因为可以取很多件,所以是和自己这一行比较,而且是从可以放下这个物品开始往后循环

#include<bits/stdc++.h>
using namespace std;
int v[1005],c[1005],w[1000005];
int main()
{
    int n,V,i,j;
    cin>>n>>V;
    for(i=1;i<=n;i++)
    {
        cin>>v[i]>>c[i];
    }
    for(i=1;i<=n;i++)
    {
        for(j=v[i];j<=V;j++)
        {
            w[j]=max(w[j],w[j-v[i]]+c[i]);
        }
    }
    cout<<w[V];
    return 0;
}

多重背包

这类题型每个物品都是有限个

理解方式和01背包相同,但是要注意个数不止一件,所以要加一层循环来确定是否拿这个物品

状态转移方程还是一样,就是注意有好多件

#include<bits/stdc++.h>
using namespace std;
int v[1005],c[1005],w[1000005],n[1005];
int main()
{
    int N,V,i,j,k;
    cin>>N>>V;
    for(i=1;i<=N;i++)
    {
        cin>>v[i]>>c[i]>>n[i];
    }
    for(i=1;i<=N;i++)
    {
        for(j=V;j>=v[i];j--)
        {
            for(k=1;k<=n[i]&&k*v[i]<=j;k++)
            {
                w[j]=max(w[j],w[j-k*v[i]]+k*c[i]);
            }
        }
    }
    cout<<w[V];
    return 0;
}
posted @ 2022-07-13 19:33  zyzzzzlh  阅读(60)  评论(1)    收藏  举报