普通背包 完全背包 多重背包 分组背包

背包问题

还有一个依赖背包暂时没学,基础dp应该用不到吧……

1.普通背包

已知 n n n件物品的体积和价值,每一件最多用一次,总体积不能超过 v o l vol vol,问最大价值

核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案

for (int i=1;i<=n;i++)
{
    for (int j=vol;j>=p[i].w;j--)
    {
        dp[j]=max(dp[j],dp[j-p[i].w]+p[i].val);
    }
}

2.完全背包

已知 n n n件物品的体积和价值,每一件可以随便用,总体积不能超过 v o l vol vol,问最大价值

核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案

for (int i=1;i<=n;i++)
{
    for (int j=p[i].w;j<=vol;j++)
    {
        dp[j]=max(dp[j],dp[j-p[i].w]+p[i].val);
    }
}

3.多重背包

已知 n n n件物品的体积和价值和数量,总体积不能超过 v o l vol vol,问最大价值

核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案

for (int i=1;i<=n;i++)
{
    for (int j=0;j<p[i].num;j++)
    {
        for (int k=vol;k>=p[i].w;k--)
        {
            dp[k]=max(dp[k],dp[k-p[i].w]+p[i].val);
        }
    }
}

4.分组背包

已知物品的价值和体积,分成 K K K个组,每个组只能最多取一件,总体积不能超过 v o l vol vol,问最大价值

核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案

for (int i=1;i<=K;i++)//每个组
{
    for (int k=vol;k>=0;k--)
    {
        for (int j=0;j<group[i].size();j++)
        //每个组里面每一个物品,用vector或者数组存
        {
            int x=group[i][j];
            if (k>=w[x])
            {
                dp[k]=max(dp[k],dp[k-w[x]]+val[x]);
            }
        }
    }
}

例题1

HDU1171

其实每一个多重背包也可以看成是普通背包来做,把具有多个数量的物品拆成很多个单一物体就可以了,这个思想叫啥也说不上来

大致题意:一共有N组数据,包含设备的价值和数量,把这些设备均分,使得分成的两堆价值差异尽量小

分析:先求出设备总价值量 s u m = ∑ ( w [ i ] ∗ n u m [ i ] ) sum=\sum(w[i]*num[i]) sum=w[i]num[i],然后在体积为 s u m / 2 sum/2 sum/2的背包中求就可以了

做法1:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x
#define mem(a,x) memset(a,x,sizeof a)
using namespace std;
const int maxn=2e6+7;
int dp[maxn],n,x,y;
vector<int >v;
int main()
{
    while(~scanf("%d",&n)&&n>-1)
    {
        int sum=0;
        mem(dp,0);
        v.clear();
        rep(i,1,n)
        {
            scanf("%d%d",&x,&y);
            sum+=x*y;
            while(y--)v.pb(x);
        }
        int sum1=sum/2;
        for (int i=0;i<v.size();i++)
        {
            for (int j=sum1;j>=v[i];j--)
            {
                dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
            }
        }
        cout<<max(dp[sum1],sum-dp[sum1])<<" "<<min(dp[sum1],sum-dp[sum1])<<endl;
    }
    return 0;
}

做法2:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x
#define mem(a,x) memset(a,x,sizeof a)
using namespace std;
const int maxn=2e6+7;
int dp[maxn],n,x,y;
struct node
{
    int x;
    int num;
} p[maxn];
int main()
{
    while(~scanf("%d",&n)&&n>-1)
    {
        mem(dp,0);
        int sum=0;
        rep(i,1,n)
        {
            scanf("%d%d",&x,&y);
            p[i].x=x;
            p[i].num=y;
            sum+=x*y;
        }
        for (int i=1; i<=n; i++)
        {
            for (int j=0; j<p[i].num; j++)
            {
                for (int k=sum/2; k>=p[i].x; k--)
                {
                    dp[k]=max(dp[k],dp[k-p[i].x]+p[i].x);
                }
            }
        }
        cout<<max(dp[sum/2],sum-dp[sum/2])<<" "<<min(dp[sum/2],sum-dp[sum/2])<<endl;
    }
    return 0;
}

例题2

P1164 小A点菜

虽然也是背包问题,但需要进一步的理解

大致题意:给出N个菜,兜里有M块钱,问有多少种买菜方案,使得钱刚好花完。

根据题目的数据,可以枚举在位置i剩余 x ( 1 ≤ x ≤ m ) x(1\leq x \leq m) x(1xm)块钱的情形,买或者不买为转移条件

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=1e4+7;
const int INF=1e9;
const ll INFF=1e18;
ll dp[101][maxn],a[maxn],n,m,ans=0;
int main()
{
    scanf("%lld%lld",&n,&m);
    rep(i,1,n)scanf("%lld",&a[i]);
    mem(dp,0);
    dp[1][m]=1;
    if (m>=a[1])dp[1][m-a[1]]=1;
    rep(i,2,n)
    {
        rep(j,1,m)
        {
            if (j>=a[i])dp[i][j-a[i]]+=dp[i-1][j];
            dp[i][j]+=dp[i-1][j];
        }
    }
    rep(i,1,n)ans+=dp[i][0];
    WW(ans);
}

例题3

P1616 疯狂的采药

多重背包模板题

你可能感兴趣的:(基础dp)