HDU 2844:Coins(多重背包)

来源:互联网 发布:js实现select 编辑:程序博客网 时间:2024/05/17 04:45

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2844

有 N 种物品和一个容量为 V 的背包。第 i 种物品最多有 ci 件可用,每件耗费的 空间是 wi,价值是 vi。求解将哪些物品装入背包可使这些物品的耗费的空间总和不超 过背包容量,且价值总和最大。这样的是多重背包。

多重背包有的暴力就是在01背包的基础上多一重循环:for(k=1;k<=c[i];k++);
使 dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);

但是这样做大多会超时,所以就有了二进制的思想。
我们把第 i 个物品分割成多个01背包。也就是分成:2^0,2^1,2^2,2^(k-1),c[i]+1-2^k.
比如有一种物品有13件,就分成:1,2,4,6 的4件物品。

#include"stdlib.h"#include"stdio.h"#include"string.h"#include"iostream"using namespace std;int dp[100005];         //数组太小会越界int main(){    int n,m;    while(scanf("%d %d",&n,&m)!=EOF)    {        if(n==0&&m==0)break;        int a[105],c[105],t=0;        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        for(int i=1;i<=n;i++)            scanf("%d",&c[i]);        memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)        {            if(c[i]*a[i]>m)                              //此条件成立可以看作是完全背包                for(int j=a[i];j<=m;j++)                    dp[j]=max(dp[j],dp[j-a[i]]+a[i]);            else            {                int k=1,s=c[i];                while(s>k)                               //二进制思想                {                    for(int j=m;j>=a[i]*k;j--)                    {                        dp[j]=max(dp[j],dp[j-a[i]*k]+a[i]*k);                    }                    s=s-k;                    k=k*2;                }                for(int j=m;j>=a[i]*s;j--)                    dp[j]=max(dp[j],dp[j-a[i]*s]+a[i]*s);            }        }        /*for(int i=1;i<=m;i++)            printf("%d ",dp[i]);        printf("\n");*/                         //测试        for(int i=1;i<=m;i++)            if(dp[i]==i)                t++;        printf("%d",t);        printf("\n");    }    return 0;}
0 0
原创粉丝点击