# Poj 1787 Charlie's Change(多重背包 或者 记录的完全背包)

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <ctime>
#include <cmath>

using namespace std;
const int N = 10010;
const int INF = 0x7fffffff;
int dp[N];
int n;
int id[4]={1,5,10,25};
int v[4],ans[4];
struct thing{
int kk[100];
int nk;
}thi[4];
void ZeroOnePack(int w,int vi){
for(int i=n;i>=vi;--i){
if(dp[i-vi]==-INF) continue;
dp[i] = max(dp[i],dp[i-vi] + w);
//		cout<<"ZOP  dp["<<i<<"]:"<<dp[i]<<endl;
}
}
void CompletePack(int vi){
for(int i=vi;i<=n;++i){
dp[i] = max(dp[i], dp[i-vi]+1);
}
}
int main()
{
//freopen("/home/user/桌面/in","r",stdin);
int flag=0;
while(scanf("%d%d%d%d%d",&n,&v[0],&v[1],&v[2],&v[3])==5){
flag = 0;
if(n!=0) flag=1;
if(n==0) for(int i=0;i<4;++i)
if(v[i]){ flag=1; break;}
if(!flag) break;

for(int i=0;i<4;++i){
ans[i] = 0; thi[i].nk=0;
}

for(int i=1;i<=n;++i) dp[i] = -INF;
dp[0]=0;

for(int i=0;i<4;++i){
//			if(v[i]*id[i]>=n){
//				CompletePack(id[i]);
//				continue;
//			}
int m=v[i],k=1;
while(k<m){
ZeroOnePack(k,k*id[i]);
thi[i].kk[thi[i].nk++] = k;
m -= k;
k = 2*k;
}
ZeroOnePack(m,m*id[i]);
thi[i].kk[thi[i].nk++] = m;
}
if(dp[n]==-INF){
continue;
}
int nnn = n;

for(int i=3;i>=0;--i){
for(int j=thi[i].nk-1;j>=0;--j){
int temp = id[i]*thi[i].kk[j];
if(n <  temp) continue;
if(dp[n] == dp[n - temp] + thi[i].kk[j]){
ans[i]+=thi[i].kk[j];
n -= temp;
}

//				cout<<" n;"<<n<<endl;
}
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[0],ans[1],ans[2],ans[3]);
//		cout<<" dp["<<nnn<<"]:"<<dp[nnn]<<endl;
}
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}

(1)如何记录某面值硬币在钱为j时所使用的个数.
(2)如何记录路径.

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <ctime>
#include <cmath>

using namespace std;
const int N = 10010;
const int INF = 0x7fffffff;
int num[4], val[4]={1, 5, 10, 25};
int dp[N], path[N], used[N], ans[100];
int main()
{
//freopen("/home/user/桌面/in","r",stdin);
int n;
while(scanf("%d%d%d%d%d",&n, &num[0], &num[1], &num[2], &num[3])==5){
if(n==0&&num[0]==0&&num[1]==0&&num[2]==0&&num[3]==0) break;

for(int i=1;i<=n;++i) dp[i] = -INF;
memset(path,-1,sizeof(path));

for(int i=0;i<4; ++i){
memset(used,0,sizeof(used));
for(int j=val[i]; j<=n; ++j){
if(dp[j-val[i]]!=-INF&&dp[j]<dp[j-val[i]] + 1&&used[j-val[i]]<num[i]){
dp[j] = dp[j-val[i]] + 1;
path[j] = j - val[i];
used[j] = used[j-val[i]] + 1;
}
}
}
//		for(int i=0;i<=n;++i) cout<<"path["<<i<<"]:"<<path[i]<<endl;

if(dp[n] == -INF){
}

memset(ans,0,sizeof(ans));
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[1],ans[5],ans[10],ans[25]);
}
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}

- -!!)

• 本文已收录于以下专栏：

## POJ 1787 - Charlie's Change(完全背包＋路径记录)

Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he o...

Charlie's Change

## POJ-1787 Charlie's Change (完全背包+输出方案 入门题)

• hmc0411
• 2017年10月30日 22:55
• 155

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

Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he oft...

## POJ 1787 Charlie's Change 记录路径的多重背包

Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3499   Accepted:...

## POJ 1787 Change 多重|完全背包

Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3895   Accepted:...

## poj1787 Charlie's Change（多重背包+路径）

http://poj.org/problem?id=1787 题意：查理想买咖啡，咖啡销售机只支持三种硬币，分别是1分、5分、10分、15分。然后给出查理拥有的四种硬币的个数，求查理最多可以消耗多少...

## oj1787Charlie's Change(多重背包+记录路径，每个包恰好被填满的基础上每个包的钱币的个数尽量多)

Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he oft...

举报原因： 您举报文章：Poj 1787 Charlie's Change(多重背包 或者 记录的完全背包) 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)