• POJ 3040 Allowance【贪心】


    POJ 3040

    题意:

    给奶牛发工资,每周至少 C 元。约翰手头上有面值V_i的硬币B_i个,这些硬币的最小公约数为硬币的最小面值。求最多能发几周?

    分析:

    贪心策略是使多发的面额最小(最优解)。分三个阶段:

    1. 首先面额不小于C的硬币属于没办法节约的类型,先统统发掉。

    2. 然后对硬币面额从大到小尽量凑得接近C,允许等于或不足C,但是不能超出C。

    3. 接着按硬币面额从小到大凑满C(凑满的意思是允许超出一个最小面值,ps此处的最小面值指的是硬币剩余量不为0的那些硬币中的最小面值),凑满之后得出了最优解,发掉,进入步骤2.

    这样就保证了每次都是当前的最优解,这个题很好地体现了贪心法的精髓。

    从大到小排序,只要不超额就能放多少就放多少,最后再从小的开始找一个放进去能超额的。

    正确性证明:

    因为大的是小的倍数,所以大的放进去不超额一定要放进去,因为小的不管怎么取,再超过c之前一定会凑成这个大的面额,那么用大的代替一定更优。第一步做完之后,那么现在一定要再放进去一个硬币,那么选择最小的并且能大于c的也一定是最优的。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=22;
    int need[maxn];
    struct node
    {
        int v,b;
        bool operator <(const node & x) const
        {
            return v>x.v;
        }
    }coin[maxn];
    
    int main()
    {
        int n,c;
        while(scanf("%d %d",&n,&c)!=EOF)
        {
            for(int i=1;i<=n;i++)
                scanf("%d %d",&coin[i].v,&coin[i].b);
            sort(coin+1,coin+1+n);
            int ans=0;
            while(1)
            {
                memset(need,0,sizeof(need));
                int sum=c;
                for(int i=1;i<=n;i++)
                {
                    int tmp = sum/coin[i].v;
                    need[i]=min(tmp,coin[i].b);
                    sum-=need[i]*coin[i].v;
                }
                if(sum>0)
                {
                    for(int i=n;i>=1;i--)
                    {
                        if(coin[i].b&&coin[i].v>=sum)// 从小到大找一个面值大于剩余sum的
                        {
                            need[i]++;
                            sum=0;
                            break;
                        }
                    }
                }
                if(sum>0)break;
                int weeks=2e9;
                for(int i=1;i<=n;i++)
                {
                    if(need[i])
                        weeks=min(weeks,coin[i].b/need[i]);
                }
                for(int i=1;i<=n;i++)
                    if(need[i])
                        coin[i].b-=weeks*need[i];
                ans+=weeks;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    作业三:代码规范、代码复审、PSP
    第二周学习进度表
    作业二:Github注册过程
    作业二:源程序版本管理软件和项目管理软件的优缺点
    作业二:四则运算
    408笔记--操作系统
    408笔记--计算机网络
    408笔记--计算机组成原理
    408笔记--数据结构
    2020 PAT秋季甲级考试(91分)-记
  • 原文地址:https://www.cnblogs.com/demian/p/6560926.html
Copyright © 2020-2023  润新知