挑战程序设计竞赛2.2习题:Allowance POJ - 3040

Allowance

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 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.

这道题目着实难看出怎么下手,我们都知道可怜的约翰家与世隔绝,没有银行,如果某张的数额比想要给多就只能都给小贝西(不找零),那么如果面额小于想给的钱怎么办呢?题目中有一句破题的关键句子:each denomination of coin evenly divides the next-larger denomination.啥意思?就是某个面额是能被第一个比它大的面额整除的,我们先不考虑最小面额为一的情况,可以把想要兑换的钱想象成有n个最小面额构成的,当然可能存在兑换的钱不是最小面额的整数倍的情况。

如果是整数倍,那么我们把面额从大到小遍历着取,遍历每次都取得 (要给的钱是最小面额的整数倍数) / (该面额是最小面额的整数倍数) 张第i种的钱币(参考白书2.2硬币问题例题),这样可以使得值恰好满足或者略小于C。之所以从大到小,这样可以防止提前用完小面额不浪费。如果出现小于C,那么说明虽然为整数倍,但是题中给的条件没有办法刚好达到C(因为如果存在该情况,则在计算的时候就能取到了),于是乎从最小的开始寻找最小满足条件且还能取的面额,虽然会超过C,但是能保证超过的情况最少,然后寻找这样的取法最多能取多少次,如果把所有的取完,也无法使得面额超过C则找完了。(如下图)

但是,大部分情况可能没有办法被整数倍的最小面额整除,那么必定会产生剩余,其实也是一样的,先取使得小于等于C,由于此类情况必定无法满足恰好(因为不能整除)所以肯定要选一张最小且能使得值大于C的面额,取完的结束条件同上。(见下图)

为什么要把它分成无数个最小非一的面额格子呢?我们可以假设每次取一张纸币时就是取了一份格子数,如果能恰好取到C,则从大到小从小到大均可以做到,但是从小到大的话后面每次取到的格子份数大,可能会出现浪费,所以从大到小取不会浪费,参考白书贪心例题硬币问题。

如果最小面额是一,那么在找到第一次可行的方法时,如果不用一无法达到C的话,此时可以用面额为一的来补。如果不够也能够使得最后找到的结果大于C的最小,所以如果存在面额为一,我们也可以假定面额最小是第一个比一大的,然后从小到大补齐的时候用一补齐缺口,如果补不齐也可以再寻找下一个比一大的使得值大于C来满足条件。

总结:先把面额排序,面额大于C的每次用一张能用完,小于C的从大到小遍历寻找解决方案,遍历时保证每种面额取值最大且均使得加入后值小于等于C,此时若小于C则不可能刚好到达C,从小到大选取一张最小且满足条件的面额,由此得到方案,计算这样能操作多少次,然后再重复本方案直到所有面额用完也无法大于等于C结束。

AC代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int INF = 0x3fffffff;
struct Node{
    int v;
    int p;
    friend bool operator <(Node x, Node y)
    {
        return x.v < y.v;
    }
}money[25];
int used[25];//本次方法每种钱使用的张数
int ans;
int start = -1;//如果全大于c则不需要管小于c的,因为没有
int main(void)
{
    int n,c;
    scanf("%d%d", &n, &c);
    for(int i = 0; i < n; i++)
    {
        scanf("%d %d", &money[i].v, &money[i].p);
    }
    sort(money, money + n);
    for(int i = n - 1; i >= 0; i--)
    {
        if(money[i].v >= c)
        {
            ans += money[i].p;
            money[i].p = 0;
        }
        else
        {
            start = i;//面额小于C的纸币的最大序号,在start之后就都是比C大的纸币
            break;
        }
    }
    while(1)
    {
        memset(used, 0, sizeof(used));//每种方法找之前每张钱币都没用过
        int goal = c;//要找到值至少为C
        for(int i = start; i >= 0; i--)
        {
            if(money[i].p == 0)
                continue;
            int t = goal / money[i].v;//相当于每次该份的最大取走份数且能使得剩余的goal >= 0
            used[i] = min(money[i].p, t);
            goal -= used[i] * money[i].v;
            if(goal == 0)//能刚好取完,就完成了一种方法
                break;
        }
        if(goal > 0)//没办法使用现有条件刚刚好达到C
        {
            for(int i = 0; i <= start; i++)//把从小到大全加上直到刚好大于C为止
            {
                if(money[i].p > used[i])
                {
                    int temp = min(money[i].p - used[i], (goal + money[i].v - 1) / money[i].v); // (goal + money[i].v - 1) / money[i].v就是假设第i种数量无限,要取几张能使得值恰好大于C
                    goal -= money[i].v * temp;
                    used[i] += temp;
                }
            }
        }
        if(goal > 0)//所有钱币都用完了还是没办法大于等于C
            break;
        int maxcopy = INF;//判断这样的操作能搞几次
        for(int i = 0; i <= start ; i++)
            if(used[i])
                maxcopy = min(maxcopy, money[i].p / used[i]);
        for(int i = 0; i <= start ; i++)
            money[i].p -= maxcopy * used[i];
        ans += maxcopy;
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/jacobfun/p/12203734.html

时间: 2024-12-07 23:34:06

挑战程序设计竞赛2.2习题:Allowance POJ - 3040的相关文章

挑战程序设计竞赛2.2习题:Stall Reservations POJ - 3190

Stall Reservations Oh those picky N (1 <= N <= 50,000) cows! They are so picky that each one will only be milked over some precise time interval A..B (1 <= A <= B <= 1,000,000), which includes both times A and B. Obviously, FJ must create a

挑战程序设计竞赛2.3习题:Cheapest Palindrome POJ - 3280

Keeping track of all the cows can be a tricky task so Farmer John has installed a system to automate it. He has installed on each cow an electronic ID tag that the system will read as the cows pass by a scanner. Each ID tag's contents are currently a

挑战程序设计竞赛2.3习题:Making the Grade POJ - 3666

A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like t

挑战程序设计竞赛2.3习题:Cow Exhibition POJ - 2184

"Fat and docile, big and dumb, they look so stupid, they aren't muchfun..."- Cows with Guns by Dana Lyons The cows want to prove to the public that they are both smart and fun. In order to do this, Bessie has organized an exhibition that will be

挑战程序设计竞赛2.4习题:Moo University - Financial Aid POJ - 2010

Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short. Not wishing to admit

挑战程序设计竞赛2.6习题:X-factor Chains POJ - 3421

Given a positive integer X, an X-factor chain of length m is a sequence of integers, 1 = X0, X1, X2, …, Xm = X satisfying Xi < Xi+1 and Xi | Xi+1 where a | b means a perfectly divides into b. Now we are interested in the maximum length of X-factor ch

挑战程序设计竞赛3.1习题:Moo University - Financial Aid POJ - 2010

(原题见POJ2010) 这道题我之前采用了优先队列+预处理的方法求解(https://www.cnblogs.com/jacobfun/p/12244509.html),现在用二分的办法进行求解. 一开始我很纳闷,采用二分求解本题,如果二分的mid值不符合条件,按照二分右边界应该为mid - 1(我采用前闭后闭的二分),那么如果mid + xxx(xxx大于0)可以呢?(考虑mid不行是因为左边最小加起来大了,mid ~ mid + xxx中有极小值,使得mid + xxx的左边可以满足,那么

挑战程序设计竞赛3.2习题:Bound Found POJ - 2566

Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration (that must be going through a defiant phase: "But I want to use feet, not meters!"). Each signal seems to come in two

POJ 3420 Quad Tiling 题解 《挑战程序设计竞赛》

POJ 3420 Quad Tiling贴瓷砖:4*N的地板上用2*1的瓷砖铺满,求所有方案数对M求余.3.4熟练掌握动态规划矩阵的幂久违地上了节课,太无聊,只好刷一题.假设S[n]表示填满n时的方案数,有S[0]=1.定义矩阵M[p][q] := 边缘p和边缘q可以拼合时取1,否则取0所谓的可以拼合表示,两个边缘拼起来后长度为1(为2就拼接不起来了),且内部缝隙可以用2*1的瓷砖填满.那么M就有一些简单的性质了,比如M的第一行应该是:0 0 0 0 0 0... 继续阅读:码农场 » POJ