您的位置:首页 > 其它

POJ1787:Charlie's Change(记录路径的多重背包)

2013-07-25 16:36 441 查看
Description
CharlieisadriverofAdvancedCargoMovement,Ltd.Charliedrivesalotandsoheoftenbuyscoffeeatcoffeevendingmachinesatmotorests.Charliehateschange.Thatisbasicallythesetupofyournexttask.

YourprogramwillbegivennumbersandtypesofcoinsCharliehasandthecoffeeprice.Thecoffeevendingmachinesacceptcoinsofvalues1,5,10,and25cents.TheprogramshouldoutputwhichcoinsCharliehastousepayingthecoffeesothatheusesas
manycoinsaspossible.BecauseCharliereallydoesnotwantanychangebackhewantstopaythepriceexactly.

Input
Eachlineoftheinputcontainsfiveintegernumbersseparatedbyasinglespacedescribingonesituationtosolve.ThefirstintegeronthelineP,1<=P<=10000,isthecoffeepriceincents.Nextfourintegers,C1,C2,C3,
C4,0<=Ci<=10000,arethenumbersofcents,nickels(5cents),dimes(10cents),andquarters(25cents)inCharlie'svalet.Thelastlineoftheinputcontainsfivezerosandnooutputshouldbegeneratedforit.

Output
Foreachsituation,yourprogramshouldoutputonelinecontainingthestring"ThrowinT1cents,T2nickels,T3dimes,andT4quarters.",whereT1,T2,T3,T4arethenumbersofcoinsofappropriatevaluesCharlieshoulduseto
paythecoffeewhileusingasmanycoinsaspossible.InthecaseCharliedoesnotpossessenoughchangetopaythepriceofthecoffeeexactly,yourprogramshouldoutput"Charliecannotbuycoffee.".

SampleInput
125312
160001
00000

SampleOutput
Throwin2cents,2nickels,0dimes,and0quarters.
Charliecannotbuycoffee.

题意:给出总价值,然后给出价值为1,5,10,25的价值的钱币的数量,问能够达到需求的总价值需要的金钱数目最多的方案

思路:乍一看是多重背包,事实上也确实是多重背包,但是由于要输出方案,所以我一直没有想到方法,看了人家的代码,才知道别人记录路径的方法挺神奇的

详细注释在代码中


#include<stdio.h>
#include<string.h>
#include<algorithm>
usingnamespacestd;

constintN=10010;
intdp[100000],sum,v[5]={1,5,10,25},ans[30],path[10010];
//dp数组装的是存放钱的总数目,ans则是每种钱的数目,path用来记录路径
voidZeroOnePack(intpos,intk)
{
inti;
for(i=sum;i>=k*v[pos];i--)
{
if(dp[i-k*v[pos]]+k>dp[i])
{
dp[i]=dp[i-k*v[pos]]+k;
path[i]=pos*N+(i-k*v[pos]);
}
}
}

voidCompletePack(intpos)
{
inti;
for(i=v[pos];i<=sum;i++)
{
if(dp[i-v[pos]]+1>dp[i])
{
dp[i]=dp[i-v[pos]]+1;
path[i]=pos*N+(i-v[pos]);
}
}
}

voidMultiplePack()
{
inti,j,k;
for(i=0;i<4;i++)
{
if(v[i]>sum)
return;
if(v[i]*ans[i]>=sum)
CompletePack(i);
else
{
intcnt=ans[i];
for(j=1;j<=cnt;j*=2)
{
ZeroOnePack(i,j);
cnt-=j;
}
if(cnt)
ZeroOnePack(i,cnt);
}
}
}

intmain()
{
inti,j,k;
while(~scanf("%d",&sum),sum)
{
for(i=0;i<4;i++)
scanf("%d",&ans[i]);
for(i=1;i<=sum;i++)
dp[i]=-N;
dp[0]=0;
MultiplePack();
if(dp[sum]<0)
{
printf("Charliecannotbuycoffee.\n");
continue;
}
memset(ans,0,sizeof(ans));
while(sum)
{
/*由01背包中的path[i]=pos*N+(i-k*v[pos]);可知,s1相当于pos
s2相当于i-k*v[pos]
而完全背包pos*N+(i-v[pos]);中,s1相当于pos
s2相当于i-v[pos]
*/
ints1=path[sum]/N;//记录现在改放的是多少钱
ints2=path[sum]%N;//记录剩余钱数
ans[v[s1]]+=(sum-s2)/v[s1];
sum=s2;
}
printf("Throwin%dcents,%dnickels,%ddimes,and%dquarters.\n",ans[1],ans[5],ans[10],ans[25]);
}

return0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: