HDU5527:Too Rich(DFS & 贪心 & 思维)

23 篇文章 0 订阅

Too Rich

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1613    Accepted Submission(s): 413


Problem Description
You are a rich person, and you think your wallet is too heavy and full now. So you want to give me some money by buying a lovely pusheen sticker which costs  p dollars from me. To make your wallet lighter, you decide to pay exactly  p  dollars by as many coins and/or banknotes as possible.

For example, if  p=17  and you have two  $10  coins, four  $5  coins, and eight  $1  coins, you will pay it by two  $5  coins and seven  $1  coins. But this task is incredibly hard since you are too rich and the sticker is too expensive and pusheen is too lovely, please write a program to calculate the best solution.
 

Input
The first line contains an integer  T  indicating the total number of test cases. Each test case is a line with 11 integers  p,c1,c5,c10,c20,c50,c100,c200,c500,c1000,c2000 , specifying the price of the pusheen sticker, and the number of coins and banknotes in each denomination. The number  ci  means how many coins/banknotes in denominations of  i  dollars in your wallet.

1T20000
0p109
0ci100000
 

Output
For each test case, please output the maximum number of coins and/or banknotes he can pay for exactly  p  dollars in a line. If you cannot pay for exactly  p  dollars, please simply output '-1'.
 

Sample Input
  
  
3 17 8 4 2 0 0 0 0 0 0 0 100 99 0 0 0 0 0 0 0 0 0 2015 9 8 7 6 5 4 3 2 1 0
 

Sample Output
  
  
9 -1 36
 

Source
题意:给若干个不同面值硬币,求凑成指定面额的最多硬币数量。

思路:比较巧妙地搜素,首先题目可以转化为拿走最少的硬币使得剩下硬币总额满足要求。那么按照贪心肯定是从面值最大的先拿,为什么这里直接贪心会正确呢?留意到题目给的面值前面的恰好是后面的因子,也就是说,大面值的能拿就拿走,否则还要小面值的凑成它,比如能拿50就拿50,否则以后还要拿5个10凑成50。还有一个问题,20不是50的因子,200不是500的因子,但是20却是50+50的因子,200却是500+500的因子,这意味着拿50和500的时候,还要考虑拿少一个硬币的情况,给20或200的硬币留空间,否则将会漏掉情况,如20,20,20,50凑60块这种数据。

# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
LL a[]={0,1,5,10,20,50,100,200,500,1000,2000}, b[13];
LL ans;
void dfs(int cur, LL tot, LL cnt)
{
    if(tot < 0) return;
    if(cur == 0)
    {
        if(tot == 0)
            ans = min(ans, cnt);
        return;
    }
    LL tmp = min((LL)b[cur], tot/a[cur]);
    dfs(cur-1, tot-tmp*a[cur], cnt+tmp);
    if(tmp) dfs(cur-1, tot-(tmp-1)*a[cur], cnt+tmp-1);

}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        LL tot = 0, sum = 0, all = 0; ans = INF;
        scanf("%lld",&sum);
        for(int i=1; i<=10; ++i) scanf("%lld",&b[i]), tot += a[i]*b[i], all += b[i];
        if(tot < sum)
        {
            puts("-1");
            continue;
        }
        dfs(10, tot-sum, 0);
        if(ans == INF) puts("-1");
        else
            printf("%lld\n",all-ans);
    }
    return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值