HDU-3348-coins

HDU-3348-coins

传送门

这一道题是一道贪心的题目哦~最近一直在写贪心啦

题目大意:给你一个p,是你需要花的钱,给你面值为1元,5元,10元,50元,100元的纸币多少张,已经给出,问能不能用最少的张数和最多的张数支付这个所需要花的钱p,如果可以输出最少的张数和最多的张数,如果不行,输出-1 -1

本题思路:这个求最少的张数的时候我们直接用很平常的贪心策略解决就好啦,就是尽可能往大的面值纸币选择,然后至于最多的纸币张数,我们可以换一种角度考虑,就是我们可以把所给了多少张纸币算出来,用num保存,所给的总共多少钱用sum保存,如果我们计算出支付 sum - p 所需要花费的最少的张数,那么我们剩下的纸币就是支付我们p的最多的张数!!(是不是这样思考的!!)。反向思维哦~
还有一个注意的点就是,我的代码部分solve()函数是解决需要最少的纸币数,如果无法凑成这个数目那么返回的是-1,在最后输出处理的时候需要特判一下,在计算最多的纸币张数的时候,用总共的纸币张数-函数返回的值,如果函数返回-1的话,那么我们输出的就是错误的答案,所以只要有某一次函数返回为-1,都需要输出为-1 -1。就是这个点需要注意以下啦~

然后就是我在书上看到的最少硬币模型中其实如果每一步选择硬币的操作是局部最优的,但是局部最优不能得到全局最优。
一个最简单的判断标准:任一 一面值的纸币,大于比他小的所有硬币的面值之和,可以用贪心法

最后是代码部分啦~

#include <bits/stdc++.h>
using namespace std;

int a[10] = {0, 1, 5, 10, 50, 100};
int v[10];

int solve(int s)
{
	int ans = 0;
	for (int i = 5; i >= 1; i--)
	{
		if (s >= a[i])
		{
			int t = s / a[i];
			s -= a[i] * min(t, v[i]);
			ans += min(t, v[i]);
		}
	}
	if (s)
	{
		return -1;
	}
	return ans;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int p;
		int sum = 0, num = 0;
		cin >> p;
		for (int i = 1; i <= 5; i++)
		{
			scanf ("%d", &v[i]);
			num += v[i];
			sum += v[i] * a[i];
		} 
		int minn = 0;
		int maxx = 0;
		minn = solve(p);
		maxx = solve(sum - p);
		if (minn == -1 || maxx == -1)
		{
			 cout << "-1 -1" << endl;
		}
		else
		{
			cout << minn << " " << num - maxx << endl;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值