您的位置:首页 > 其它

poj 1787 Charlie's Change

2013-07-06 22:30 351 查看
思路: 多重背包

分析:

1 题目给定的数据明显就是多重背包,但是题目有个难点就是输出路径,0/1背包里面有输出路经的方法,做法做法是通过记录前面的状态

2 这一题还要求输出每种硬币的个数,那么这边利用mark数组,mark[i][0] = pos 表示的是当前这个状态是取的是第pos个物品,mark[i][pos] = x;表示的是当前这个状态增加了x个物品

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 10010;
const int N = 5;
const int INF = 0x3f3f3f3f;

int v
= {0,1,5,10,25};
int sum , num
, dp[MAXN];
int ans
, path[MAXN] , mark[MAXN]
;

void zeroOnePack(int pos , int k , int cost , int weight){
for(int i = sum ; i >= cost ; i--){
dp[i] = max(dp[i] , dp[i-cost]+k);
if(dp[i] == dp[i-cost]+1){
path[i] = i-cost;
mark[i][0] = pos;
mark[i][pos] = k;
}
}
}

void completePack(int pos , int cost , int weight){
for(int i = cost ; i <= sum ; i++){
dp[i] = max(dp[i] , dp[i-cost]+1);
if(dp[i] == dp[i-cost]+1){
path[i] = i-cost;
mark[i][0] = pos;
mark[i][pos] = 1;
}
}
}

void multiplePack(int pos , int cost,int weight,int amount){
if(cost*amount >= sum){
completePack(pos , cost , weight);
return;
}
int k = 1;
while(k < amount){
zeroOnePack(pos , k , k*cost , k*weight);
amount -= k;
k *= 2;
}
zeroOnePack(pos , amount , amount*cost , amount*weight);
}

int main(){
while(scanf("%d",&sum)){
scanf("%d%d%d%d",&num[1],&num[2],&num[3],&num[4]);
if(!(sum+num[1]+num[2]+num[3]+num[4]))
break;
for(int i = 0 ; i < MAXN ; i++)
dp[i] = -INF;
dp[0] = 0;
for(int i = 1 ; i <= 4 ; i++)
multiplePack(i , v[i],v[i],num[i]);
if(dp[sum] < 0)
puts("Charlie cannot buy coffee.");
else{
int pos = sum;
memset(ans , 0 , sizeof(ans));
while(pos){
int tmp = mark[pos][0];
ans[tmp] += mark[pos][tmp];
pos = path[pos];
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[1],ans[2],ans[3],ans[4]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: