Problem D
Buying Coke
Input:StandardInput
Output: Standard Output
Time Limit: 2 Seconds
I often buy Coca-Cola from the vending machine atwork. Usually I buy several cokes at once, since my working mates also likes coke.A coke in the vending machine costs8 Swedish crowns, and the machineaccept crowns with the values1, 5 and 10. As soon as Ipress the coke button (after having inserted sufficient amount of money), Ireceive a coke followed by the exchange (if any). The exchange is always givenin as few coins as possible (this is uniquely determined by the coin set used).This procedure is repeated until I've bought all the cokes I want. Note that Ican pick up the coin exchange and use those coins when buying further cokes.
Now, what is the least number of coins I mustinsert, given the number of cokes I want to buy and the number of coins I haveof each value? Please help me solve this problem while I create some harderproblems for you. You may assume that the machine won't run out of coins andthat I always have enough coins to buy all the cokes I want.
The first line in the input contains the numberof test cases (at most 50). Each case is then given on a line by itself.A test case consists of four integers:C (the number of cokes I want tobuy),n1,n5, n10(the number of coins of value1,5 and 10, respectively).The input limits are1 <=C <= 150, 0 <= n1<= 500,0 <=n5 <= 100 and 0 <= n10<= 50.
For each test case, output a line containing a singleinteger: the minimum number of coins needed to insert into the vending machine.
3 2 2 1 1 2 1 4 1 20 200 3 0 |
5 3 148
|
题目意思是说可乐8块钱1瓶,你有1块,5块,10块的,如果你丢进去钱超过8块,它会自动找你尽可能少的钱的张数,问你最少用几张钱能买到需要的可乐。
以前做记忆化搜索的时候,就觉得和DP基本差不多,只是求解的顺序不同,搜索函数几个参数保存状态的数组就开几维。。平时用递推比较多,现在才发现记忆化搜索真神奇。。
这道题一开始想的是开个四维数组,递推求出每个状态。结果根本开不下这么大的数组(而且其实就算开下了也没有必要计算其中的很多状态)。看了别人的,发现是记忆化搜索,并且只用三维数组(dp[x][y][z],代表三种钱的张数并且还需要买c瓶可乐)保存计算过的状态。。其实确实可以,因为是通过递归一步一步求的,原来的总钱数减去每个状态的总钱数一定是8的倍数,这样dp[x][y][z]确定了还需要买的可乐也就确定了(c=C-(最开始总钱数-现在总钱数)/8)。也就是说根本不需要四维的数组。但是从底向上递推的话没有四维数组不好递推,用记忆化搜索就简单了,函数里有四个参数,保存状态的数组是三维。如果计算过或者c=0就返回。
有时候不好递推的时候记忆化搜索真的好用(时间复杂度和递推是一样的,常数级的时间用的多一些,但是省去了很多不必要又不好算的情况)~
这道题还有个特别要注意的地方,你给它3个1块和1个10块,它会找你一个5块。
#include<cstring> #include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<queue> #define INF 0x3f3f3f3f using namespace std; int dp[800][250][100]; int DP(int c,int n1,int n2,int n3){ int &ans=dp[n1][n2][n3]; if(ans) return ans; if(!c) return 0; ans=INF; if(n1>=8) ans=min(ans,DP(c-1,n1-8,n2,n3)+8); if(n1>=3&&n2>=1) ans=min(ans,DP(c-1,n1-3,n2-1,n3)+4); if(n2>=2) ans=min(ans,DP(c-1,n1+2,n2-2,n3)+2); if(n3>=1) ans=min(ans,DP(c-1,n1+2,n2,n3-1)+1); if(n1>=3&&n3>=1) ans=min(ans,DP(c-1,n1-3,n2+1,n3-1)+4); return ans; } int main(){ freopen("in.txt","r",stdin); int T,C,N1,N2,N3; scanf("%d",&T); while(T--){ memset(dp,0,sizeof(dp)); scanf("%d%d%d%d",&C,&N1,&N2,&N3); printf("%d\n",DP(C,N1,N2,N3)); } return 0; }