[Usaco2005 Oct]Allowance 津贴

针对一个具体的支付问题,本文提供了一种贪心算法解决方案。该问题要求计算在给定不同面额硬币的情况下,如何支付特定金额才能使得支付周数最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 compute the maximum number of weeks he can pay Bessie.
作为对勤勤恳恳工作的贝茜的奖励,约翰已经决定开始支付贝茜一个小的每周津贴。 约翰有n(1N20)种币值的硬币,面值小的硬币总能整除面值较大的硬币。比如说,币值有如下几种:1美分,5美分,10美分,50美分……利用给定的这些硬币,他将要每周付给贝茜一定金额的津贴C(1C108)
请帮他计算出他最多能给贝茜发几周的津贴。

Input
第1行:2个用空格隔开的整数nC
第2到n+1行:每行两个整数表示一种币值的硬币.第一个整数V(IV108),表示币值。
第二个整数B(1B106),表示约翰拥有的这种硬币的个数。

Output
一个整数,表示约翰付给贝茜津贴得最多的周数。

Sample Input
3 6
10 1
1 1 00
5 1 20

Sample Output
111

样例说明
约翰想要每周付给贝茜6美分。他有1个10美分的硬币、100个1美分的硬币、120个5美分的硬币。约翰可以第一周付给贝茜一个10美分的硬币,接着的10周每周付给贝茜2个5美分硬币,接下来的100周每周付给贝茜一个1美分的硬币和1个5美分的硬币。共计111周。

HINT

Source
Silver

解题思路
贪心,具体请见代码

代码

#include <cstdio>
#include <algorithm>

const int maxn=20;

struct data
{
    int price,lim;

    bool operator <(const data &b) const
    {
        return price<b.price;
    }
};

int n,c,ans;
data d[maxn+2];

int main()
{
    scanf("%d%d",&n,&c);
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d",&d[i].price,&d[i].lim);
    }
    std::sort(d+1,d+n+1);//按价格从小到大排序
    while(n)
    {
        if(d[n].price>=c)//如果当前钞票的面值大于需要的面值
        {
            ans+=d[n].lim;//最优方案一定是每周付一张当前面值的钞票
            n--;
        }
        else
        {
            break;
        }
    }
    while(1)
    {
        int r=0;
        for(int i=n; i>0; i--)
        {
            while((d[i].price+r<=c)&&(d[i].lim>0))
            {//如果当前面值的钞票不会使需要支付的面值过量
                d[i].lim--;//那么使用当前钞票
                r+=d[i].price;
            }
        }
        if(r<c)
        {//如果不够支付一周
            for(int i=1; i<=n; i++)
            {//从剩下的面值当中挑一张最小的
                if((r+d[i].price>=c)&&(d[i].lim>0))
                {
                    d[i].lim--;
                    r+=d[i].price;
                    break;
                }
            }
        }
        if(r>=c)
        {
            ans++;
        }
        else
        {//如果还不够,说明所有钞票已经用完
            printf("%d\n",ans);
            return 0;
        }
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值