Allowance - 完美诠释贪心 - POJ 3040

链接

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

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值