zoj 2156

给出价格P,和五种硬币的数量,求最多 用多少个硬币组成P。

多重背包的应用,需要注意的是要统计每种硬币用了多少种,用father数组记录j(价格)是由哪个得到的。num数组表示此时有多少个硬币。

代码:

#include <stdio.h>
#include <string.h>
int dp[10010];
int p,c[5],ans[6],w[6]={0,1,5,10,25};


int father[10003],num[10003];
int mulity(int weight,int amount)
{
    if(weight*amount>=p)
    {
        for(int j=weight;j<=p;j++)
        {
            if(dp[j-weight]!=-1&&dp[j]<dp[j-weight]+1)
            {
                dp[j]=dp[j-weight]+1;
                father[j]=j-weight;
                num[j]=1;
            }
        }
    }
    else
    {
        int k=1;
        while(k<amount)
        {
            for(int i=p;i>=k*weight;i--)
            {
                if(dp[i-k*weight]!=-1&&dp[i]<dp[i-k*weight]+k)
                {
                    dp[i]=dp[i-k*weight]+k;
                    father[i]=i-k*weight;
                    num[i]=k;
                }
            }
            amount-=k;
            k+=k;
        }
        for(int i=p;i>=amount*weight;i--)
        {
            if(dp[i-amount*weight]!=-1&&dp[i]<dp[i-amount*weight]+amount)
            {
                dp[i]=dp[i-amount*weight]+amount;
                father[i]=i-amount*weight;
                num[i]=amount;
            }
        }
    }
}
int main()
{
    while(scanf("%d %d %d %d %d",&p,&c[1],&c[2],&c[3],&c[4])!=EOF)
    {
        if(p+c[1]+c[2]+c[3]+c[4]==0)
            break;
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        memset(father,-1,sizeof(father));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=4;i++)
        {
            mulity(w[i],c[i]);
        }
        if(dp[p]==-1)
            printf("Charlie cannot buy coffee.\n");
        else
        {
            for(int i=p;i!=0;i=father[i])
            {
                int k=(i-father[i])/num[i];
                for(int j=1;j<=4;j++)
                {
                    if(k==w[j])
                        ans[j]+=num[i];
                }
            }
            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[1],ans[2],ans[3],ans[4]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值