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;
}