题意:
有1,5,10,20,50,100,200,500,1000,2000十种面值的钱币各ci个,现在要凑出p元,问最多可以用多少钱币凑出
思路:
取最多的钱币,就是要多取面额小的钱币。
从小贪心到大面额,存在一个问题:
例如:
110 19个1 2个20 2个50这组数据
我们无法正确的从1开始贪心,以保证贪心的结果是正确的。
那么,我们可以转化一下思路多取面额小的钱币即少取面额大的。即在小面额的钱数足够时,能不用大面额的钱币就不用。
注意到除了20 50,200 500外,所有小面额钱币都是大面额钱币的因子,即大面额钱币都可以被足够多的小面额钱币代替,故每次取大面额钱币是独立的。
对于20 50,200 500我们可以将50 ,500转化为100,1000,通过枚举多取一张来保证操作的独立性。
代码:
#include <bits/stdc++.h>
using namespace std;
long long a[11];
long long b[11]={0,1,5,10,20,50,100,200,500,1000,2000};
long long sum[10];
long long ans,tempans,n;
void dfs(long long left,int pos){
if(left<0) return ;
if(pos==0){
if(left==0) ans=max(ans,tempans);
return ;
}
long long sub=max(0LL,left-sum[pos-1]);
long long need=sub/b[pos];
if(sub%b[pos]) need++;
if(a[pos]>=need){
tempans+=need;
dfs(left-need*b[pos],pos-1);
tempans-=need;
}
//for 20 50 200 500
need++;
if(a[pos]>=need){
tempans+=need;
dfs(left-need*b[pos],pos-1);
tempans-=need;
}
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
for(int i=1;i<=10;i++) scanf("%lld",&a[i]);
sum[0]=0;
for(int i=1;i<=10;i++) sum[i]=sum[i-1]+b[i]*a[i];
ans=-1;
tempans=0;
dfs(n,10);
printf("%lld\n",ans);
}
}