思路: 多重背包
分析:
1 题目给定的数据明显就是多重背包,但是题目有个难点就是输出路径,0/1背包里面有输出路经的方法,做法做法是通过记录前面的状态
2 这一题还要求输出每种硬币的个数,那么这边利用mark数组,mark[i][0] = pos 表示的是当前这个状态是取的是第pos个物品,mark[i][pos] = x;表示的是当前这个状态增加了x个物品
分析:
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[N] = {0,1,5,10,25}; int sum , num[N] , dp[MAXN]; int ans[N] , path[MAXN] , mark[MAXN][N]; 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; }