题目链接
题意
给定值p,然后告诉你面额为1,5,10,20,50,100,200,500,1000,2000的钱分别有多少张,要求用尽可能多的张数组合出p这个值,如果组合不出来输出-1。
思路
也许是因为是A题,所以开始做的时候就看了这题,想了挺久的。
一开始想的是直接贪心面额小的,后面发现可能会导致能组合出来的却会输出-1,后面想到可以先从大到小的面额贪心先把值组合出来,然后再判断,能不能用剩下的小面额的钱把组合成p中的大面额的钱替换掉,因为这样做的话,ans的值一定是增加的,然后想了好久的递归。。。。
有个地方导致错了一次,因为50不是20的倍数,但是(50*2)是 20的倍数,所以用小面额替换大面额的时候要判断一下,然后我只考虑了20*3替换50,没考虑20*4替换50。。。。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
LL p;
LL ans;
LL c[20];
LL v[20] = {0,1,5,10,20,50,100,200,500,1000,2000};
LL sum[20];
void dfs(LL n, LL num, LL cnt) //三个参数分别为,还需组合的钱数,此次的面额,已用的钱有几张
{
if(n < 0){ //小于0时组合不成立
return ;
}
if(num == 0){
if(n == 0){ //已判断过最小的面额能不能替换大面额,如果此时还剩下要组合的钱数为0
ans = max(ans,cnt); //判断当前的ans和cnt哪个更大
}
return ;
}
LL t = max(n-sum[num-1],(LL)0); //判断当前剩下的钱能否用于替换,如果不能前者结果会<0
LL flag = t/v[num]; //计算需要几张
if(t%v[num]) // 2和5的关系需要判断,两张20不足够代替一张50,至少还需要多加一张,200同理
flag++;
if(flag<=c[num]) //判断剩余的张数是否还足够
dfs(n-flag*v[num],num-1,cnt+flag);
flag++; // 还是2和5的关系,因为最多可以用4张20代替一张50,200同理,其他面额多加一张对时间也没太大影响。。。
if(flag<=c[num])
dfs(n-flag*v[num],num-1,cnt+flag);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
memset(sum,0,sizeof(sum));
scanf("%lld",&p);
for(int i=1; i<=10; i++){
scanf("%lld",&c[i]);
sum[i] = sum[i-1]+c[i]*v[i]; //先把前缀和记录下来
}
ans = -1;
dfs(p,10,0);
printf("%lld\n",ans);
}
return 0;
}