nyoj DivideingJewels(多重背包)

来源:互联网 发布:怎么安装电视直播软件 编辑:程序博客网 时间:2024/06/03 10:15

DivideingJewels

原题链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=546
方法一:
转换成01背包问题,防止超时要进行一些必要的剪枝和二进制优化
代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int v[100010],dp[100010];int main(){    int m=1,i;    while(1)    {        memset(dp,0,sizeof(dp));        int a[15],sum=0,j,k=0;        for(i=1; i<=10; i++)        {            scanf("%d",&a[i]);            sum+=a[i]*i;        }        if(!sum)            break;        if(sum&1)            printf("#%d:Can't be divided.\n\n",m++);        else        {            for(i=1; i<=10; i++)            {                for(j=1; j<=a[i]; j<<=1)//二进制优化,相当于把重量相同的n件物品转换成不同重量的有且只有1件的物品,即转换成01背包。例:13可以分为 1(2^0)、2(2^1)、4(2^2)、6,因为1、2、4、6这四个数可以组合成1—13中的所有数字)                  {                    v[k++]=i*j;                    a[i]-=j;                }                if(a[i]>0)                {                    v[k++]=a[i]*i;                }            }            sum>>=1;            for(i=0; i<k; i++)                for(j=sum; j>=v[i]; j--)                    dp[j]=max(dp[j],dp[j-v[i]]+v[i]);            if(dp[sum]==sum)                printf("#%d:Can be divided.\n\n",m++);            else                printf("#%d:Can't be divided.\n\n",m++);        }    }    return 0;}

方法二:
对于多重背包,可以先对每种物品判断是否超出背包容量,1.如果该种物品超出,则可以当做完全背包来做,因为完全背包不就是装满该容量的背包,物品可以任意取嘛,都一样的。2.如果没有超出,则对于该种物品来说,当做01背包来做,但是这里将该种物品又进行了捆绑分组(2进制优化,时间复杂度可降到O(V*Σlog(n[i])))
代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int dp[100010];int sum,j;void zeroonepack(int c,int w){    for(j=sum;j>=c;j--)        dp[j]=max(dp[j],dp[j-c]+w);}void complatepack(int c,int w){    for(j=c;j<=sum;j++)        dp[j]=max(dp[j],dp[j-c]+w);}void multipiepack(int c,int w,int n){    if(c*n>=sum)        complatepack(c,w);    else    {        int k=1;        while(k<n)        {            zeroonepack(c*k,w*k);            k<<=1;            n-=k;        }        if(n>0)            zeroonepack(c*n,w*n);    }}int main(){    int m=1,i;    while(1)    {        memset(dp,0,sizeof(dp));        int a[12];        sum=0;        for(i=1;i<=10;i++)        {            scanf("%d",&a[i]);            sum+=a[i]*i;        }        if(!sum)            break;        if(sum&1)            printf("#%d:Can't be divided.\n\n",m++);        else        {            sum>>=1;            for(i=1;i<=10;i++)                multipiepack(i,i,a[i]);                if(dp[sum]==sum)                    printf("#%d:Can be divided.\n\n",m++);                else                    printf("#%d:Can't be divided.\n\n",m++);        }    }    return 0;}
ps:多重背包模板题。。
1 0
原创粉丝点击