Allowance

来源:互联网 发布:uboot源码详解 编辑:程序博客网 时间:2024/05/11 17:36

链接

POJ 3040

题意

题意 : 给你N种货币的面额和大小,再给出一个值为C。任意组合作为一天的工资
而限制是Sum >= C,问你用这些钱,最多能发多少天的工资。

思路

  • 1. 按照面额排序
  • 2. 取出所有面额大于等于C的货币
  • 3. 从大到小取,尽可能的靠近C(不能大于C)
  • 4. 从小大取,超过C就进行累加
  • 5. 重复34步直到无法取出

AC代码

#include<queue>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define SC(x) scanf("%d",&x);#define pr(x)  cout << x << endl;#define mem(arr,v) memset(arr,v,sizeof arr);#define bug(x) cout << "#x = " << x <<endl;const int inf = 0x3f3f3f3f;const int maxn = 1000;typedef long long ll;using namespace std;typedef struct Money {    int V;    int num;} M;M a[maxn],my;int use[maxn];bool cmp(M & lhs, M &rhs) {    return lhs.V < rhs.V;}int main() {    int N,C;    cin >> N >> C;    for(int i = 0 ; i < N ; i++) {        cin >> my.V >> my.num;        a[i] = my;    }    sort(a,a + N,cmp);    ll res = 0;    for(int i = N - 1 ; i >= 0 ; i--) {                     // >= C面额 的直接取完        if(a[i].V >= C) {            res += a[i].num;            a[i].num = 0;        }    }    while(1) {        //初始化        int sign = 0;        int cnt  = C;        mem(use,0)        for(int i = N - 1 ; i >= 0 ; i--) {                     //从大往小取   靠近但不超过 C            int num = a[i].num , V = a[i].V;            if(num == 0)     continue;            int m = min(cnt / V , num);            cnt -= m * V;            use[i] = m;            if(cnt == 0) {                sign = 1;                break;            }        }        if(cnt > 0) {                                          // 从小往大取   超过C就停下            for(int  i = 0 ; i < N ; i++) {                int num = a[i].num , V = a[i].V;                if(num == 0)    continue;                while(use[i] < num) {                    cnt -= V;                    use[i]++;                    if(cnt <= 0) {                        sign = 1;                        break;                    }                }                if(sign)                    break;            }        }        if(!sign)   break;                                   //凑不到C元发工资 结束        int minn = inf;        for(int i = 0; i < N ; i++) {            if(use[i]){                minn = min(minn,a[i].num / use[i]);            }        }        res += minn;        for(int i = 0 ; i < N ; i++ ) {            if(use[i]) {//              cout << " " << a[i].num << " " << a[i].V << endl;                a[i].num -= minn * use[i];                use[i] = 0;            }        }    }    pr(res)//  printf("%d\n",res);}

写完以后对贪心有了更深的理解 :

一般都要先排序,然后去寻找能够满足限制条件的贪心方法


可以刷下面的一些贪心算法再感受一下( 怒刷一套 ) :

Packets
Cleaning Shifts
Radar Installation
Stall Reservations
Yogurt factory
Stripies
Protecting the Flowers

原创粉丝点击