这题一拿到看明显用多重背包来做,之后用多重背包的二进制优化来做,给跪了,没倒腾出来,之后直接度娘之,看到大神代码说是多重背包可以用完全背包来做,而我的二进制优化就相当于01背包。看来还是看资料看的不仔细啊,要改。(不过有看大神代码说是用母函数的多项式展开来做,表示先做备忘,之后做数论在一起看吧)
这题背包的容量为价值,背包的总价值为加入的硬币数,用used[ ]数组来控制次数(由多重背包转化成完全背包),path来保存的上一个的总价值 path[v]=v-val[i];之后就ok了吧。
上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=10010;
const int INF=0x3f3f3f3f;
int used[maxn];
int dp[maxn];
int path[maxn];
int cnt[4];
int val[4]={1,5,10,25};
int main()
{
//freopen("int.txt","r",stdin);
while(1){
int n,sum=0;
scanf("%d",&n);
for(int i=0;i<4;i++){
scanf("%d",&cnt[i]);
sum+=cnt[i]*val[i];
}
memset(dp,-INF,sizeof(dp));
memset(path,0,sizeof(path));
path[0]=-1;
dp[0]=0;
if(!n&&!sum)break;
for(int i=0;i<4;i++){
memset(used,0,sizeof(used));
for(int v=val[i];v<=n;v++){
if(dp[v-val[i]]+1>dp[v]&&dp[v-val[i]]>=0&&used[v-val[i]]<cnt[i]){
dp[v]=dp[v-val[i]]+1;
used[v]=used[v-val[i]]+1;
path[v]=v-val[i];
}
}
}
int ans[100];
memset(ans,0,sizeof(ans));
if(dp[n]<0){
printf("Charlie cannot buy coffee.\n");
}
else {
while(path[n]!=-1){
ans[n-path[n]]++;
n=path[n];
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n", ans[val[0]], ans[val[1]], ans[val[2]], ans[val[3]]);
}
}
return 0;
}