poj之旅——3040

来源:互联网 发布:视频开会软件 编辑:程序博客网 时间:2024/06/16 12:18

题目描述:农夫约翰要给奶牛Bessie发工资了,每周至少 C 元。约翰手头上有面值V_i的硬币B_i个,求最多能发几周?



题解:

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

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

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

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

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


参考程序:

#include<cstdio>#include<algorithm>#include <functional>#include <limits>#include<string>#include<iostream>using namespace std;struct Node{int v,c;}end;Node coin[20];int need[20];bool cmp(Node a,Node b){return (a.v>b.v);}int main(){int N,C,week=0;scanf("%d %d",&N,&C);for (int i=0;i<N;i++)scanf("%d %d",&coin[i].v,&coin[i].c);for (int i=0;i<N;i++)if (coin[i].v>=C)week+=coin[i].c,coin[i].c=0;sort(coin,coin+N,cmp);while (true){int sum=C;memset(need,0,sizeof(need));for (int i = 0; i < N; ++i)if (sum > 0 && coin[i].c > 0){int can_use = min(coin[i].c, sum / coin[i].v);if (can_use > 0){sum -= can_use * coin[i].v;need[i] = can_use;}}for (int i = N - 1; i >= 0; --i)if (sum > 0 && coin[i].c > 0){int can_use = min(coin[i].c - need[i],(sum + coin[i].v - 1) / coin[i].v); if (can_use > 0){sum -= can_use * coin[i].v;need[i] += can_use;}}if(sum > 0)break; int add_up = numeric_limits<int>::max(); for (int i = 0; i < N; ++i){if (need[i] == 0)continue;add_up = min(add_up, coin[i].c / need[i]);}week += add_up;for (int i = 0; i < N; ++i){if (need[i] == 0)continue;coin[i].c -= add_up * need[i];}   }   printf("%d",week);return 0;}


0 0