Allowance

题解:
你有很多张面额不同的纸币,你每个星期要给奶牛至少c元,问你用现在的钱最多给奶牛多少周。
这个题的感觉就是贪心,想了两三种方案感觉都不太对,后来发现这真的是很好的一个题,首先,
将大于等于c的面额的钱直接每个星期给奶牛一张,将面额大于等于c的前去除,然后从大到小开始选择,要选择的金额尽可能的接近c,如果刚好能够凑足c就作为当前的一种方案,如果不能凑足c那就再从小的开始选,要选出一种的总额不少于c但尽量接近c作为当前的方案,然后计算如果按照如此方案最多可以给奶牛多少周,然后按照相同的方法再选方案,一直选到选择的金额不能凑足c为止。

将硬币从小到大排序,从后往前扫描,那种直接能支付的大硬币就直接支付了。对于小硬币,我们一次一次地凑,先从大往小凑,看一周的剩余价值中最多可以使用多少这种硬币,并记录(而且要减去已经凑好的)然后如果还没凑够,就从小向大一个一个地加上,看能不能达到,如果能就记录并开始下一轮的凑,如果不能就退出(此时一定再也不能凑出了,请想一想)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node
{
	__int64 v,m;
}coin[22];

bool cmp(node a,node b)
{
	return a.v > b.v;
}
int main()
{
	__int64 n,c;
	__int64 ans;
	while (~scanf ("%I64d %I64d",&n,&c))
	{
		for (int i = 0 ; i < n ; i++)
		scanf ("%I64d %I64d",&coin[i].v,&coin[i].m);
		sort (coin , coin + n , cmp);
		ans = 0;
		bool flag = true;		//是否能继续拿
		for (int i = 0 ; i < n ; i++)
		{
			if (coin[i].v >= c)
				ans += coin[i].m;
			else								//首先从大往小拿
			{
				while (coin[i].m)
				{
					int t = 0;		//已经拿的钱数
					for (int j = i ; j < n ; j++)
					{
						if (!coin[j].m)		//没钱了就跳过
							continue;
						while (coin[j].m && t < c)
						{
							t += coin[j].v;
							coin[j].m--;
						}
						if (t == c)		//如果正好发完就发了
						{
							ans++;
							break;
						}
						else		//否则就再往下搜
						{
							t -= coin[j].v;
							coin[j].m++;
						}
					}
					if (t == c)
						continue;
					for (int j = n - 1 ; j >= i ; j--)		//不够再从小往大拿
					{
						if (!coin[j].m)
							continue;
						if (t + coin[j].m * coin[j].v >= c)		//够拿就拿
						{
							ans++;
							coin[j].m -= (c - t + coin[j].v - 1) / coin[j].v;//结果向上取整
							//表示的是  (c-t)/coin[j].v;							
							t=c;//管它后来是多少钱,就按c算
							break;                   // 优化使之不为零
						}
						else		//不够就先拿完
						{
							t += coin[j].m * coin[j].v;
							coin[j].m = 0;
						}
					}
					if (t < c)		//如果还不够拿,则无法再发工资
					{
						flag = false;
						break;
					}
				}
			}
			if (!flag)
				break;
		}
		printf ("%I64d\n",ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值