POJ 3040Allowance【难,贪心】

来源:互联网 发布:淘宝客服的上班时间 编辑:程序博客网 时间:2024/06/03 18:33

Allowance
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 2924 Accepted: 1180

Description

As a reward for record milk production, Farmer John has decided to start paying Bessie the cow a small weekly allowance. FJ has a set of coins in N (1 <= N <= 20) different denominations, where each denomination of coin evenly divides the next-larger denomination (e.g., 1 cent coins, 5 cent coins, 10 cent coins, and 50 cent coins).Using the given set of coins, he would like to pay Bessie at least some given amount of money C (1 <= C <= 100,000,000) every week.Please help him ompute the maximum number of weeks he can pay Bessie.

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Each line corresponds to a denomination of coin and contains two integers: the value V (1 <= V <= 100,000,000) of the denomination, and the number of coins B (1 <= B <= 1,000,000) of this denomation in Farmer John's possession.

Output

* Line 1: A single integer that is the number of weeks Farmer John can pay Bessie at least C allowance

Sample Input

3 610 11 1005 120

Sample Output

111

Hint

INPUT DETAILS: 
FJ would like to pay Bessie 6 cents per week. He has 100 1-cent coins,120 5-cent coins, and 1 10-cent coin. 

OUTPUT DETAILS: 
FJ can overpay Bessie with the one 10-cent coin for 1 week, then pay Bessie two 5-cent coins for 10 weeks and then pay Bessie one 1-cent coin and one 5-cent coin for 100 weeks.

Source

USACO 2005 October Silver


大概思路我倒是自己想出来了,就是代码我没写出来。(白说……)

最后看别人的代码,一开始没看懂后来调试了一遍懂了。那个代码写得相当巧妙!!超厉害!!

代码里面我加一些注释,最重要的还是要自己动手调试吧。调试一下思路立刻清晰了。


题意:FJ要给Bessie发零用钱,现在FJ有一些面值的硬币。他每周必须至少给Bessie发价值C的零用钱,问他最多能给发几周。


题解:先把单值大于C的零用钱直接发出去。

剩下的钱,首先从大拿到小,但是拿的钱不能多于C。等于C直接处理掉,小于C的继续下一步。

然后,再从剩下的钱里从小拿到大,这一步大于C也没关系,发出去就行。(从小开始拿,才能使超过C的部分尽量小!)


#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>using namespace std;int n,c;struct it {int money,num;}a[25];bool cmp(it x,it y){return x.money>y.money;}int use[25];int main(){int i;while(~scanf("%d%d",&n,&c)){for(i=0;i<n;i++)scanf("%d%d",&a[i].money,&a[i].num);sort(a,a+n,cmp);int sum=0;for(i=0;i<n;i++)//把大于的直接发出去{if(a[i].money>=c){sum+=a[i].num;a[i].num=0;}}while(1)//每次的循环,相当于凑出一个方案来。{int flag=0;int temp=c;memset(use,0,sizeof(use));//每次循环重新记录这回花了多少钱for(i=0;i<n;i++)//因为前面把单个大于C的都取出去了,所以这一步每一个的钱肯定都不会大于Cif(a[i].num){int k=temp/a[i].money;//算出在这种情况下,需要多少个a[i],记为kint mi=min(a[i].num,k);//对比a[i]里的钱的个数和k谁小。如果k小,那么这个循环继续,继续找可以凑成的temp-=mi*a[i].money;  //如果k大的话,那么说明a[i]可以直接凑出C,这时候能跳出循环,处理这一项。use[i]=mi;if(temp<=0){flag=1;//符合条件标记break;}}if(temp>0)//题解最后一步。{for(i=n-1;i>=0;i--)if(a[i].num>use[i])//如果现有的钱大于他已经花出去的钱,那么再继续。小于等于的话,说明已经花完这部分了{while(use[i]<a[i].num){temp-=a[i].money;//从小面额一点一点减去,能少超过C就少超过use[i]++;if(temp<=0){flag=1;//得到符合条件,标记break;}}if(temp<=0) break;}}if(!flag) break;//如果这一轮小于C(凑不够钱),直接跳出。int mx=1000000000;for(i=0;i<n;i++)if(use[i])mx=min(mx,a[i].num/use[i]);//寻找每一回里面最小的钱币数sum+=mx;for(i=0;i<n;i++)if(use[i])a[i].num-=mx*use[i];//删掉已经发出去的钱币}printf("%d\n",sum);}return 0;}



0 0
原创粉丝点击