链接
题意
题意 : 给你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