POJ 3040 Allowance 贪心

来源:互联网 发布:mac mini 安装 win10 编辑:程序博客网 时间:2024/05/20 08:43

很厉害的题目,没看题解之前一直忽略了题目中的一个性质,下一个硬币面额总是上一个硬币面额的倍数。我也不清楚如果看到了这一点之后我会不会想出答案。

这道题目最优策略要考虑两个因素:

1.取得相同面额时,硬币数量越少越好

2.相同硬币数量时,面额越少越好(首先总面额要大于C)

这个限制条件是很难满足的,我自己想的一些贪心策略都可以举反例证伪(举得反例有一些是不符合倍数要求的)。

但是在题目特殊的倍数要求下,这个条件就变得可以满足了。

贪心策略如下,证明本人目前还没想出来:

1.先按面值从小到大排序

2.从后往前取,在保证总面额小于等于C的前提下尽量多取

3.从前往后取,直到取得总面额大于等于C

很奇妙的是,这个贪心策略加上题目特殊的倍数要求,就变得总是正确的了,里面的证明肯定很精彩,以后如果我想起来了再补充吧。

代码如下:

#include <map>#include <queue>#include <cstdio>#include <vector>#include <cstdlib>#include <iostream>#include <algorithm>#define MAX_N 10005using namespace std;struct data{    int value;    int number;    bool operator < (const data& b) const    {        return value < b.value;    }};typedef long long int ll;int main(){    //freopen("in.txt", "r", stdin);    int N, C;    data dat[MAX_N];    while (~scanf("%d%d", &N, &C))    {        for (int i = 0; i < N; i++)            scanf("%d%d", &dat[i].value, &dat[i].number);        sort(dat, dat + N);        ll ans = 0;        for (int i = N - 1; i >= 0; i--)//大于C的硬币先处理        {            if (dat[i].value >= C)            {                ans += dat[i].number;                dat[i].number = 0;            }            else                break;        }        while (1)        {            int need = C;            for (int i = N - 1; i >= 0; i--)            {                if (dat[i].number && need >= dat[i].value)                {                    int k = need / dat[i].value;                    k = min(k, dat[i].number);                    need -= k * dat[i].value;                    dat[i].number -= k;                }            }            for (int i = 0; i <= N - 1; i++)            {                if (dat[i].number && need)                {                    int k;                    if (need % dat[i].value)                        k = (need + dat[i].value) / dat[i].value;                    else                        k = need / dat[i].value;                    k = min(k, dat[i].number);                    if (need >= k * dat[i].value)                        need -= k * dat[i].value;                    else                        need = 0;                    dat[i].number -= k;                }            }            if (need == 0)                ans++;            else                break;        }        printf("%lld\n", ans);    }    return 0;}


0 0
原创粉丝点击