算法竞赛模板 动态规划之背包DP

① 01背包

有n件物品和一个容量为v的背包。第i件物品的价值是c[i],体积是w[i]。求解将哪些物品装入背包可使价值总和最大。

这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t,n,v,i,j,w[1005],c[1005],dp[1005];
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof dp);
        cin>>n>>v;
        for(i=1;i<=n;i++)
            scanf("%d",&c[i]);
        for(i=1;i<=n;i++)
            scanf("%d",&w[i]);
for(i=1;i<=n;i++) for(j=v;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+c[i]); cout<<dp[v]<<endl; } return 0; }

 

② 完全背包

有n种物品和一个容量为v的背包,每种物品都有无限件。第i种物品的价值是c[i],体积是w[i]。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t,n,v,i,j,w[1005],c[1005],dp[1005];
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof dp);
        cin>>n>>v;
        for(i=1;i<=n;i++)
            scanf("%d",&c[i]);
        for(i=1;i<=n;i++)
            scanf("%d",&w[i]);
            
        for(i=1;i<=n;i++)
            for(j=w[i];j<=v;j++)
                dp[j]=max(dp[j],dp[j-w[i]]+c[i]); 
        
        cout<<dp[v]<<endl;
    }
    return 0;
}

 

③ 多重背包

(1) 有n种物品和一个容量为v的背包。第i种物品最多有num[i]件,每件价值是c[i],体积是w[i]。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t,v,n,i,j,k,dp[105],num[105],c[105],w[105];
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof dp);
        cin>>n>>v;
        for(i=1;i<=n;i++)
            scanf("%d%d%d",&c[i],&w[i],&num[i]);

        for(i=1;i<=n;i++)
            for(j=1;j<=num[i];j++)
                for(k=v;k>=w[i];k--)
                    dp[k]=max(dp[k],dp[k-w[i]]+c[i]);

        cout<<dp[v]<<endl;
    }
    return 0;
}

 

(2) 2个人平分n种物品第i种物品最多有num[i]件,每件物品价值为c[i],保证两者拥有物品的价值差距最小

ps:物品总价值÷2,再去做多重背包。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MAX 100005
using namespace std;
int dp[MAX],c[MAX],num[MAX];
int main()
{
    int i,j,k,n,v,vhalf;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        v=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&c[i],&num[i]);
            v+=c[i]*num[i];   //所有物品的总价值 
        }
        vhalf=v/2; 
        for(i=1;i<=n;i++)
            for(j=1;j<=num[i];j++)
                for(k=vhalf;k>=c[i];k--)
                    dp[k]=max(dp[k],dp[k-c[i]]+c[i]);
                    
        cout<<v-dp[vhalf]<<" "<<dp[vhalf]<<endl;
    }
    return 0;
}

 

④ 多重背包二进制优化

有n种船只,每种船只的载货量为w[i],每种船只的数量为2^c[i]-1。接下来有q次询问,每次问有多少种载货方式可以填满容量s,结果取模。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e4;
const int mod=1e9+7;
typedef long long ll;
int w[25],c[25];
ll dp[MAX+5];
int main()
{
    int n,i,T,q,s,j,k;
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--)
    {
        cin>>n>>q;
        for(i=1;i<=n;i++)
            cin>>w[i]>>c[i];
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(i=1;i<=n;i++)       //共n种船
        {
            int t=1;
            for(j=1;j<=c[i];j++)//每种船有2^c[i]-1只
            {
                for(k=MAX;k>=t*w[i];k--)
                    dp[k]=(dp[k]+dp[k-t*w[i]])%mod;
                t<<=1;
            }
        }
        while(q--)
        {
            cin>>s;
            cout<<dp[s]<<endl;
        }
    }
    return 0;
}

 

posted @ 2018-04-20 22:33  真想不出名字了  阅读(343)  评论(0编辑  收藏  举报