多重背包

来源:互联网 发布:森系服装品牌 知乎 编辑:程序博客网 时间:2024/05/16 17:18

实际上是01背包和完全背包的结合体,但在进行01背包时使用了二进制的思想来进行优化。

void zero_one_pack(int w1,int v1){    for(int j=res;j>=w1;j--)        dp[j]=max(dp[j],dp[j-w1]+v1);}void complete_pack(int w1,int v1){    for(int j=w1;j<=res;j++)        dp[j]=max(dp[j],dp[j-w1]+v1);}void multiple_pack(){    memset(dp,0,sizeof(dp));    for(int i=1;i<=6;i++)    {        if(w[i]*i>=res)            complete_pack(i,i);        else        {            int k=1;            while(k<w[i])            {                zero_one_pack(k*i,k*i);                w[i]-=k;                k<<=1;            }            zero_one_pack(w[i]*i,w[i]*i);        }    }}

POJ 2392

将最大高度a进行一下排序之后进行多重背包

#include <iostream>#include <cstring>#include <cstdio>#include <string>#include <algorithm>using namespace std;#define inf 0x3f3f3f3f#define PI acos(-1.0)typedef long long ll;const int maxn=4e4+10;struct node{    int h,a,c;}t[505];int dp[maxn],sum[maxn];bool cmp(node a,node b){    return a.a<b.a;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        for(int i=0;i<n;i++)            cin >> t[i].h >> t[i].a >> t[i].c;        sort(t,t+n,cmp);        memset(dp,0,sizeof(dp));        dp[0]=1;        int maxm=0;        for(int i=0;i<n;i++)        {            memset(sum,0,sizeof(sum));            for(int j=t[i].h;j<=t[i].a;j++)            {                if(dp[j-t[i].h]&&sum[j-t[i].h]<t[i].c&&!dp[j])                {                    dp[j]=1;                    sum[j]=sum[j-t[i].h]+1;                    maxm=max(maxm,j);                }            }        }        cout << maxm << endl;    }    return 0;}



POJ 1276

dp数组记录当前和是否用过

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>using namespace std;#define inf 0x3f3f3f3f#define PI acos(-1.0)typedef long long ll;const int maxn=1e5+10;int dp[maxn],an[maxn],av[maxn],c,n;int main(){    while(scanf("%d%d",&c,&n)!=EOF)    {        for(int i=0;i<n;i++)            cin >> an[i] >> av[i];        if(!c||!n)        {            cout << 0 << endl;            continue;        }        memset(dp,0,sizeof(dp));        dp[0]=1;        int maxm=0;        for(int i=0;i<n;i++)        {            for(int j=maxm;j>=0;j--)            {                if(dp[j])                {                    for(int k=1;k<=an[i];k++)                    {                        int sum=k*av[i]+j;                        if(sum>c)                            continue;                        dp[sum]=1;                        maxm=max(maxm,sum);                    }                }            }        }        cout << maxm << endl;    }    return 0;}

POJ 1742

给定n种面值的硬币面值分别为wi个数为ci,问用这些硬币可以组成1~m之间的多少面值,多重背包的可行性问题。

#include <cstdio>#include <string>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <cmath>#include <map>#include <set>#include <list>#include <queue>#include <stack>#define inf 0x3f3f3f3f#define PI acos((double)-1)using namespace std;typedef long long ll;const int maxn=1e5+10;int a[110],c[110],n,m,dp[2][maxn];int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        if(n==0&&m==0)            break;        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        for(int i=1;i<=n;i++)            scanf("%d",&c[i]);        memset(dp,-1,sizeof(dp));        dp[0][0]=0;        for(int i=1;i<=n;i++)        {            int s=i&1;            int s1=(i+1)&1;            memset(dp[s],-1,sizeof(dp[s]));            for(int j=0;j<=m;j++)                if(dp[s1][j]>=0)                    dp[s][j]=c[i];            for(int j=a[i];j<=m;j++)            {                if(dp[s][j-a[i]]>0)                    dp[s][j]=max(dp[s][j],dp[s][j-a[i]]-1);            }        }        int cnt=0;        for(int i=1;i<=m;i++)            if(dp[n&1][i]>=0)                cnt++;        cout << cnt << endl;    }    return 0;}

POJ 3260

顾客付钱为多重背包,找零为完全背包

#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>using namespace std;#define inf 0x3f3f3f3f#define PI acos(-1.0)typedef long long ll;const int maxn=1e5+10;int w[maxn],c[maxn],n,m;ll dp1[maxn],dp2[maxn];void zero_one_pack(int w1,int v1){    for(int j=maxn;j>=w1;j--)        dp1[j]=min(dp1[j],dp1[j-w1]+v1);}void complete_pack(int w1,int v1){    for(int j=w1;j<=maxn;j++)        dp1[j]=min(dp1[j-w1]+v1,dp1[j]);}void multiple_pack(){    memset(dp1,inf,sizeof(dp1));    dp1[0]=0;    for(int i=0;i<n;i++)    {        if(c[i]*w[i]>=m)            complete_pack(w[i],1);        else        {            int k=1;            while(c[i]>k)            {                zero_one_pack(k*w[i],k);                c[i]-=k;                k<<=2;            }            zero_one_pack(c[i]*w[i],c[i]);        }    }}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        for(int i=0;i<n;i++)            cin >> w[i];        ll sum=0;        for(int i=0;i<n;i++)            cin >> c[i],sum+=c[i]*w[i];        if(sum<m)        {            cout << -1 << endl;            continue;        }        multiple_pack();        memset(dp2,inf,sizeof(dp2));        dp2[0]=0;        for(int i=0;i<n;i++)        {            for(int j=w[i];j<=maxn;j++)                dp2[j]=min(dp2[j],dp2[j-w[i]]+1);        }        ll ans=inf;        for(int i=0;i<=maxn-m;i++)            ans=min(ans,dp1[i+m]+dp2[i]);        if(ans==inf)            cout << -1 << endl;        else            cout << ans << endl;    }    return 0;}