poj 3040 Allowance
题意:
约翰有一些硬币,这些硬币中的大面值都可以被任何小于它面值的硬币的面值所整除,比如1 5 10 50等。
现在每个面值的硬币有若干个,约翰每周至少要付给他的奶牛的薪酬为C,问约翰最多可以付多少周。
思路:
贪心,一道好题。
首先从大面值的往小面值的加,不能超过C,但是一定要尽量接近C或者等于C。
之后再加最小的面值的一个硬币或者不加就可以凑够C,这个最小的面值是指数量不为0的硬币中面值最小的。
这个贪心原则是正确的,我的一个比较独特的一个证明:
因为每次都是加的面值最小的一个硬币(在从大到小加小于C的情况下),所以可以保证每次超过C的钱是最少的,也就是说浪费的钱是最少的,那么就可以剩下尽可能多的钱再去凑C。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #include <algorithm> 5 using namespace std; 6 7 struct node 8 { 9 int val,num; 10 node(){}; 11 node(int a,int b) 12 { 13 val = a; 14 num = b; 15 } 16 }; 17 18 vector<node> a; 19 20 bool cmp(node x,node y) 21 { 22 return x.val > y.val; 23 } 24 25 int main() 26 { 27 int n,c; 28 29 while (scanf("%d%d",&n,&c) != EOF) 30 { 31 a.clear(); 32 33 for (int i = 0;i < n;i++) 34 { 35 int x,y; 36 scanf("%d%d",&x,&y); 37 38 a.push_back(node(x,y)); 39 } 40 41 sort(a.begin(),a.end(),cmp); 42 43 long long ans = 0; 44 45 for (int i = 0;i < n;i++) 46 { 47 if (a[i].val >= c) 48 { 49 ans += a[i].num; 50 a[i].num = 0; 51 } 52 else 53 { 54 while (a[i].num > 0) 55 { 56 long long sum = 0; 57 58 for (int j = i;j < n;j++) 59 { 60 if (a[j].num <= 0) continue; 61 62 if (sum + a[j].val > c) continue; 63 64 while (1) 65 { 66 if (sum + a[j].val > c)break; 67 68 sum += a[j].val; 69 70 a[j].num--; 71 72 if (a[j].num <= 0) break; 73 74 if (sum == c) break; 75 } 76 } 77 78 if (sum == c) ans++; 79 else 80 { 81 for (int j = n - 1;j >= i;j--) 82 { 83 if (a[j].num <= 0) continue; 84 if (sum >= c) break; 85 86 while (1) 87 { 88 sum += a[j].val; 89 90 a[j].num--; 91 92 if (a[j].num <= 0) break; 93 94 if (sum >= c) break; 95 } 96 } 97 98 if (sum >= c) ans++; 99 else break; 100 } 101 } 102 } 103 } 104 105 printf("%lld\n",ans); 106 } 107 108 return 0; 109 }
康复训练中~欢迎交流!