您的位置:首页 > 其它

POJ 3040 Allowance 贪心

2017-02-07 22:20 274 查看
题目链接: poj 3040

贪心

看到题目的时候完全没有什么思路,这类题目做的还是太少了,完全是面向题解编程。

我的(bierende)思路:第一时间肯定是想到浪费的越少越好。

1. 当币值大于C的时候,就直接用这个硬币付工资。

2. 当币值小于C的时候,就要想一种搭配方案,使得总的价值等于或者多于C但多余的钱要尽可能少,这个就比较难想到了。

而题目中有一个条件是,大的币值能被小的整除,所以若干个小的一定能凑出大的,那么可以用一个大的或若干个小的的情况下,肯定是要选用一个大的,这样之后的搭配方案才能更好的符合”超出C的钱尽可能少“这个条件。

所以, 当当币值小于C的时候,从币值最大的开始遍历,一个小于C,那两个、三个一直到n个,直到刚好等于C或者n+1个硬币大于C,如果是后者,那就选n个,在从币值更小的硬币重复上面的过程,直到刚好等于C或者全部硬币遍历完

如果最后的全部遍历完还是不能凑到刚好等于C,那么从小到大,直到找到一个加上这个硬币刚好大于C的。如果找不到,就说明剩下的全部加起来已经没有C了,结束了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;

const int MAXN = 25;
pair<int,int> p[MAXN];//存储硬币币值和数量
int n, c;

int main()
{
while(scanf("%d%d", &n, &c) == 2)
{
for(int i=0; i<n; i++)
scanf("%d%d", &p[i].first, &p[i].second);
sort(p, p+n);//按币值从小到大排序
int ans = 0, require, need[MAXN], rest;
while(true)
{
rest = c;
memset(need, 0, sizeof(need));
for(int i=n-1; i>=0; --i)//从大到小选择
{
if(p[i].second>0)
{
require = min(p[i].second, rest/p[i].first);//需要这个币值的硬币的数量
rest -= require*p[i].first;
need[i] = require;
}
if(rest == 0) break;//刚好凑出C
}
if(rest)
{
for(int i=0; i<n; i++)//从小到大选择
{
if(p[i].second && p[i].first>=rest)//加上这个硬币(最小)就刚好大于C
{
rest = 0;
need[i]++;
break;
}
}
}
if(rest) break;//两轮选择后仍然凑不齐C,结束
int week = 1e8;//用这个方案能发多少个星期的工资
for(int i=0; i<n; i++)
{
if(need[i]) week = min(week, p[i].second/need[i]);
}
ans+=week;
for(int i=0; i<n; i++)//把用掉的硬币减去
{
if(need[i]) p[i].second -= week*need[i];
}
}
cout << ans << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: