题目:POJ - 3040
题意:
农夫要给奶牛Bessie每周津贴。农夫有N种不同面额不同数量的硬币,而且相邻大小的硬币面额存在整除关系(1分、5分、10分、50分)。他每周至少要给奶牛C分钱,计算他所有的钱最多可以给奶牛多少周。
思路:
有限的钱要维持尽量多的时间,关键在于每周尽可能少的超过最低标准。因此,对所有的硬币分两类,面额大于C的硬币一天给一个。面额小于C的硬币……没有想到合适的贪心策略了。
参考了:码农场 » POJ 3040 Allowance 题解 《挑战程序设计竞赛(第2版)》
大硬币面额是小硬币面额的倍数很重要,这意味着同等数量的一堆小硬币可以被一枚大硬币代替,这样小硬币就可以剩下来以后用,可以保证最小的浪费,所以
1. 从大到小贪心,尽量多的选择大硬币,但是不要超过所需金额c
2. 从小到大贪心。
1、2都执行完之后,如果所需的金额还是大于0,就说明硬币不够再多给一周了,break。
1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <math.h> 5 6 using namespace std; 7 8 int n; 9 int m = 0; //需要进行贪心的硬币 10 int c; 11 pair<int, int> coin[20]; 12 13 int solve() { 14 int res = 0; 15 sort(coin, coin + m); 16 int need = c; 17 while (1) { 18 for (int i = m - 1; i >= 0; --i) { 19 if (need > 0 && coin[i].second > 0) { 20 int t = min(coin[i].second, need / coin[i].first); 21 need -= t * coin[i].first; 22 coin[i].second -= t; 23 } 24 } 25 for (int i = 0; i < m; i++) { 26 if (need > 0 && coin[i].second > 0) { 27 int t = min(coin[i].second, (int)ceil((double)need / (double)(coin[i].first))); 28 need -= t * coin[i].first; 29 coin[i].second -= t; 30 } 31 32 } 33 if (need > 0) { 34 break; 35 } 36 res++; 37 need = c; 38 } 39 return res; 40 } 41 42 int main() { 43 int res = 0; 44 int v; 45 int b; 46 scanf("%d %d", &n, &c); 47 for (int i = 0; i < n; ++i) { 48 scanf("%d %d", &v, &b); 49 if (v >= c) { 50 res += b; 51 } 52 else { 53 coin[m].first = v; 54 coin[m].second = b; 55 m++; 56 } 57 } 58 res += solve(); 59 60 printf("%d\n", res); 61 return 0; 62 }