poj 3040 Allowance
目录
知识点:
贪心
解题报告
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <limits>
using namespace std;
struct Coin {
int d;
int b;
};
bool cmp(const Coin &a, const Coin &b) {
return a.d > b.d;
}
vector<Coin> v;
int N, C;
int need_count[20];
int main() {
scanf("%d %d", &N, &C);
int res = 0;
for(int i=0;i<N;i++) {
struct Coin c;
scanf("%d %d", &c.d, &c.b);
if (c.d >= C) {
res += c.b;
continue;
}
v.push_back(c);
}
sort(v.begin(), v.end(), cmp);
N = v.size();
int i, j;
while(1) {
int sum = C;
memset(need_count, 0, sizeof(need_count));
// 从大到小贪到刚好 sum 或是接近 sum
for(i=0;i<N;++i) {
if (sum > 0 && v[i].b > 0) {
int has = min(v[i].b, sum / v[i].d);
if (has > 0) {
sum -= has * v[i].d;
need_count[i] = has;
}
}
}
// 从小到大贪到 sum
for(i=N-1;i>=0;--i) {
if (sum > 0 && v[i].b > 0) {
// 允许超过一个面值来凑够 sum
int has = min(v[i].b - need_count[i], (sum+v[i].d-1) / v[i].d);
if (has > 0) {
need_count[i] += has;
sum -= has * v[i].d;
}
}
}
if (sum > 0) break;
int weeks = numeric_limits<int>::max();
for(i=0;i<N;++i) {
if (need_count[i] == 0) continue;
// 对 C 的最优解所能满足的次数,即 weeks
weeks = min(weeks, v[i].b / need_count[i]);
}
res += weeks;
// 最后更新剩余金币数量
for(i=0;i<N;++i) {
if (need_count[i] == 0) continue;
v[i].b -= weeks * need_count[i];
}
}
printf("%d\n", res);
return 0;
}
结语
经典贪心好题,重点学习贪心的思维方式