In the country of ALPC , Xiaoqian is a very famous mathematician. She is immersed in calculate, and she want to use the minimum number of coins in every shopping. (The numbers of the shopping include the coins she gave the store and the store backed to her.)
And now , Xiaoqian wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1, V2, ..., VN (1 ≤ Vi ≤ 120). Xiaoqian is carrying C1 coins of value V1, C2 coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner .But Xiaoqian is a low-pitched girl , she wouldn’t like giving out more than 20000 once.
InputThere are several test cases in the input.
Line 1: Two space-separated integers: N and T.
Line 2: N space-separated integers, respectively V1, V2, ..., VN coins (V1, ...VN)
Line 3: N space-separated integers, respectively C1, C2, ..., CN
The end of the input is a double 0.
OutputOutput one line for each test case like this ”Case X: Y” : X presents the Xth test case and Y presents the minimum number of coins . If it is impossible to pay and receive exact change, output -1.Sample Input
3 70 5 25 50 5 2 1 0 0
Sample Output
Case 1: 3题意:顾客需要v价值的物品,问,付款的硬币数最小是多少,给定n种硬币的价值和数量,当顾客付款超过v时,商家需要找钱给顾客,商家找的钱也计入硬币总数。题目中说明了商家可以找回任意价值的钱币,数量无限,需要注意题目提醒,顾客一次性付钱不超过20000.思路:这道题如果按照平常把v价值的物品作为上限(也就是背包容量),会发现无法处理付款超过v时的情况,根据题目提示,顾客一次性付款不超过20000,我们可以将20000作为背包容量,在此背包容量下,可以计算v~20000任意价值的最小付款硬币量,因为不一定超过了给定的v,钱币数量就最大或者最小,我们需要在最后遍历比较得出最小值,ans = min(ans,dp1[i]+dp2[i-v]),dp1存的是顾客付款为v时的最小硬币数,dp2存的是商家找钱为i-v时的最小硬币数。注意dp1[0]和dp2[0]我们需要初始化为0,因为一开始硬币数为0。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f #define N 20010 int dp1[N],dp2[N],value[110],num[110]; int n,v,ans; void CompletePack(int value) { int i; for(i = value; i < N ; i ++) dp1[i] = min(dp1[i],dp1[i-value]+1); return; } void ZeroOnePack(int value,int num) { int i; for(i = N-1; i >= value; i --) dp1[i] = min(dp1[i],dp1[i-value]+num); return; } int main() { int i,j,k,x,t=0; while(scanf("%d%d",&n,&v),(n+v)) { for(i = 1; i <= n; i ++) scanf("%d",&value[i]);//读入硬币价值 for(i = 1; i <= n; i ++) scanf("%d",&num[i]);//读入硬币数量 for(i = 0; i < N; i ++) { dp1[i] = inf;//初始化,因为我们所求的数量需要最小 dp2[i] = inf; } dp1[0] = dp2[0] = 0;//一开始初始化为0,数量为0 for(i = 1; i <= n; i ++)//对顾客来说,是一个多重背包的问题 { if(num[i]*value[i] > v) CompletePack(value[i]); else { k = 1; while(num[i]>0) { x = min(k,num[i]); ZeroOnePack(x*value[i],x); num[i] -= x; k*= 2; } } } for(i = 1; i <= n; i ++)//由题可知,商家的硬币数量是无限的,所以是完全背包 for(j = value[i]; j < N;j ++) dp2[j] = min(dp2[j],dp2[j-value[i]]+1); ans = inf;//我们需要最小值,所以先初始化为一个极大值 for(i = v; i < N; i ++) ans = min(ans,dp1[i]+dp2[i-v]);//顾客付款为i时,店家需要找钱i-v。 printf("Case %d: ",++t); if(ans == inf) printf("-1\n"); else printf("%d\n",ans); } return 0; }