POJ 3040 Allowance 贪心
这题目的贪心思路还是有一点细节问题的。
还没有证明,据说是因为题目给的条件是每个价格是比它小的价格的倍数才能这么贪心的。
思路如下:
假设要给奶牛的钱为C
1)从大面值到小面值一次拿钱,能拿多少拿多少。
但是注意不能拿到的钱的总和大于C
2)如果第一步拿到的钱不够C,那么就从小面值到大面值拿钱,能拿多少拿多少。
直到拿到的钱总和大于等于C
我刚开始第一步实现的比较好,但是第二步想错了。
后来才意识到大拿到的钱尽量不要超过C很多才是最优的,所以第二步要从小到大拿
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#define MAXN 11111
#define MAXM 222222
#define INF 1000000000
using namespace std;
int n, c;
typedef pair<int, int> P;
P a[22];
int use[22], sum[22];
int main()
{
scanf("%d%d", &n, &c);
for(int i = 0; i < n; i++) scanf("%d%d", &a[i].first, &a[i].second);
sort(a, a + n);
int ans = 0;
for(int i = n - 1; i >= 0; i--)
if(a[i].first >= c)
{
ans += a[i].second;
a[i].second = 0;
}
while(true)
{
int flag = 0;
int tmp = c;
memset(use, 0, sizeof(use));
for(int i = n - 1; i >= 0; i--)
if(a[i].second)
{
int k = tmp / a[i].first;
int mi = min(a[i].second, k);
tmp -= mi * a[i].first;
use[i] = mi;
if(tmp <= 0)
{
flag = 1;
break;
}
}
if(tmp > 0)
{
for(int i = 0; i < n; i++)
if(a[i].second > use[i])
{
while(use[i] < a[i].second)
{
tmp -= a[i].first;
use[i]++;
if(tmp <= 0)
{
flag = 1;
break;
}
}
if(tmp <= 0) break;
}
}
if(!flag) break;
int mx = INF;
for(int i = n - 1; i >= 0; i--)
if(use[i]) mx = min(mx, a[i].second / use[i]);
ans += mx;
for(int i = n - 1; i >= 0; i--)
if(use[i]) a[i].second -= mx * use[i];
}
printf("%d\n", ans);
return 0;
}
浙公网安备 33010602011771号