POJ 3040 Allowance(貪心,詮釋思想的好題)
阿新 • • 發佈:2019-01-06
Allowance
* 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.
* Line 1: A single integer that is the number of weeks Farmer John can pay Bessie at least C allowance
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.
題意:約翰要給他的牛貝西發工資,每天不得低於C元,約翰有n種面值的錢幣,第i種的面值為v_i,數量有b_i。問這些錢最多給貝西發多少天的工資。注意,每種面值的金錢都是下一種的面值的倍數。
題解:好題,深入瞭解貪心思想。POJ真不錯啊,刷個貪心都把我搞得不要不要的(;′⌒`)。這一題分三步解決:
1. 按照面值從大到小取,面值大於等於C的,直接取光。
2. 再按面值從大到小取,湊近C,可以小於等於C,但不能大於C。
3.最後從小到大取,湊滿C,這裡的湊滿可以等於大於C。然後將上述2,3步取到的面值全部取走,再轉入步驟2,這樣每次找到的取法就是當前最優取法,直到所剩下的金幣總價值不夠C結束。
很好的題目,很能表現貪心思想:從區域性的最優解找出總體最優解。
程式碼如下:
Time Limit:1000MS |
Memory Limit:65536K |
Total Submissions:2300 |
Accepted:945 |
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
Sample Input
3 6
10 1
1 100
5 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.
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f
using namespace std;
int use[30];//記錄當前取法的第i種面值取的個數
struct node
{
int v,b;
}a[25];
int cmp(node a,node b)
{
return a.v<b.v;
}
int main()
{
int n,c,i,cnt,ans,k,m;
while(scanf("%d%d",&n,&c)!=EOF)
{
for(i=0;i<n;++i)
scanf("%d%d",&a[i].v,&a[i].b);
sort(a,a+n,cmp);
ans=0;
for(i=n-1;i>=0;i--)//第一步,滿足大於C的面值全部取走
{
if(a[i].v>=c)
{
ans+=a[i].b;
a[i].b=0;
}
}
while(1)//每次迴圈都在找一次當前最優取法,直到剩下的總金額小於C元
{
int sign=0;
cnt=c;
memset(use,0,sizeof(use));
for(i=n-1;i>=0;--i)//第二步,從大到小取,不能超過C的值
{
if(a[i].b)
{
k=cnt/a[i].v;
m=min(k,a[i].b);
cnt-=m*a[i].v;
use[i]=m;
if(cnt==0)
{
sign=1;
break;
}
}
}
if(cnt>0)
{
for(i=0;i<n;++i)//第三步,從小到大取,湊滿C
{
if(a[i].b>use[i])
{
while(use[i]<a[i].b)
{
cnt-=a[i].v;
use[i]++;
if(cnt<=0)
{
sign=1;
break;
}
}
}
if(sign)
break;
}
}
if(!sign)
break;
m=INF;
for(i=0;i<n;++i)
{
if(use[i])//找到當前取法的能取的總次數
m=min(m,a[i].b/use[i]);
}
ans+=m;
for(i=0;i<n;++i)
{
if(use[i])
a[i].b-=m*use[i];
}
}
printf("%d\n",ans);
}
return 0;
}