题意:

给出一个价格n和一些零钱的数量。求最多用多少零钱凑出这个n。

思路:

用最少的零钱凑会比用最多的零钱凑好考虑。

如果零钱是1,5,10,50,100,200,1000,2000的话,就可以从大到小直接贪心取,就是每个零钱都是后面一个的约数的时候就可以直接贪心取。但是题目这种情况就不能这么做了,比如20,20,20,50,50,要取110,如果用这种策略的话,是凑不到110的,实际上是可以20+20+20+50的,50要少取一张。所以搜索一下两种情况,取满和取满-1。

代码:

typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll val[10]={1,5,10,20,50,100,200,500,1000,2000};
ll num[10];
ll ans;
void dfs(int id,ll sum,ll cnt)//当前种类/钱数/张数
{
    if(sum==0)
    {
        //printf("cnt=%lld\n",cnt);
        ans=min(ans,cnt);
        return;
    }
    if(id==-1)return;
    ll temp=min(num[id],sum/val[id]);
    //printf("id=%d sum=%lld temp=%lld\n",id,sum,temp);
    dfs(id-1,sum-temp*val[id],cnt+temp);
    if(temp>0)dfs(id-1,sum-(temp-1)*val[id],cnt+temp-1);
}
int main()
{
    int t;
    ll sum;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&sum);
        ll tot=0;//总钱数
        ll cnt=0;//总张数
        for(int i=0;i<10;i++)
        {
            scanf("%lld",&num[i]);
            tot+=val[i]*num[i];
            cnt+=num[i];
        }
        sum=tot-sum;
        if(sum<0)
        {
            printf("-1\n");
            continue;
        }
        //printf("sum=%lld cnt=%lld\n",sum,cnt);
        ans=INF;
        dfs(9,sum,0);
        //printf("ans=%lld\n",ans);
        if(ans==INF)printf("-1\n");
        else printf("%lld\n",cnt-ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

__builtin_系列函数 Previous
HDU6444 循环节+单调队列优化dp Next