HDOJ2844-Coins(DP)

来源:互联网 发布:linux acl 编辑:程序博客网 时间:2024/06/06 02:28

题意:你有n种面值的硬币,告诉你每种硬币的数量,问这些硬币能拼成多少不超过m的面额。

思路:多重背包。当某种硬币的总额大于背包容量时进行完全背包,否则进行二进制拆分进行01背包。最后统计f[i]==i的数量,即恰好能凑出金额为i的情况总数。详解请参考背包九讲。

代码如下:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int f[100010];int v[105],s[105];//面值,数量int max(int x,int y){    return x>y?x:y;}void work(int n,int m){    int i,j,k,t,ans;    memset(f,0,sizeof(f));    for(i=0;i<n;i++) scanf("%d",&v[i]);    for(i=0;i<n;i++) scanf("%d",&s[i]);    for(i=0;i<n;i++)    {        if(v[i]*s[i]>=m)        {            //若某种金币的总金额大于总价,则直接进行完全背包            for(j=v[i];j<=m;j++)                f[j]=max(f[j],f[j-v[i]]+v[i]);        }        else        {            k=1;            while(k<s[i])            {                //将物品进行二进制拆分,进行01背包操作                for(j=m;j>=v[i]*k;j--)                    f[j]=max(f[j],f[j-v[i]*k]+v[i]*k);                s[i]-=k;                k<<=1;            }            //对二进制拆分后剩下的物品进行01背包            for(j=m;j>=v[i]*s[i];j--)                f[j]=max(f[j],f[j-v[i]*s[i]]+v[i]*s[i]);        }    }    ans=0;    for(i=1;i<=m;i++)        ans+=(f[i]==i);    printf("%d\n",ans);}int main(){    int n,m;    while(scanf("%d%d",&n,&m),n||m)        work(n,m);    return 0;}



0 0
原创粉丝点击