您的位置:首页 > 其它

Too Rich HDU - 5527 (思维题+贪心)

2017-06-14 10:49 423 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5527


Too Rich

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 1253    Accepted Submission(s): 299


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 pdollars
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.

1≤T≤20000
0≤p≤109
0≤ci≤100000

 

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

2015ACM/ICPC亚洲区长春站-重现赛(感谢东北师大)

题目大意:某人在钱包中有面值为1,5,10,20,,等的硬币分别为num[i]张。然后要这个人要付款p元,问恰好能凑成这p元所需要的最多的硬币的张数,如果不能准确的凑成p元输出-1。

题解:首先想到的就是用贪心,先考虑花小面值的钱,但是这样要用dfs去遍历+回溯。还有一种办法就是看看钱包中所有的钱数减去要付款的这p元后还剩下的钱。然后去凑剩下的钱,这就要凑剩下的钱需要的最少的张数了。那么最少的张数就从面值大的开始贪心就行了。如果想用了大面值得就会使得小面值得不需要的话,那说明一个问题就是大面值的总是小面值的倍数关系,这样才保证可以先使用大面值的钱。但是在面值中20,50,200,500,是没有倍数关系的,那怎么办呢?可以将20,200或者50,500的化成与其他成倍数的关系的。在这里我化的是50,500的,对于50面值的而言,可以假设50用的是奇数张还是偶数张,然后再两张两张的用(也就是当成100的用了)。若是奇数的话就先用一张,不然就直接两张两张的用。500同理。这样去判断能不能凑成总的-p元。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;
typedef long long LL;
LL num[15],a[]= {1,5,10,20,50,100,200,500,1000,2000};
LL work(LL p)
{
LL ans=0;
for(int i=9; i>=0; i--)
{
if(p==0)break;
if(num[i]<=0)continue;
if(a[i]==50||a[i]==500)
{
if(num[i]>=2)
{
LL m=num[i]/2;
LL temp=min(p,a[i]*2*m);///两张两张的用
LL k=temp/(a[i]*2);
p=p-k*a[i]*2;
ans+=k*2;
}
}
else
{
LL temp=min(p,a[i]*num[i]);
LL k=temp/a[i];
p=p-k*a[i];
ans+=k;
}
}
if(p==0)return ans;
return -1;
}
int main()
{
int T;
LL p,sum,ret,ans,d;
scanf("%d",&T);
while(T--)
{
sum=ret=0;
scanf("%lld",&p);
for(int i=0; i<10; i++)
{
scanf("%lld",&num[i]);
sum+=num[i]*a[i];
ret+=num[i];
}
if(p>sum)
{
printf("-1\n");
continue;
}
p=sum-p;

///剩下p元
ans=-1;
///50,500都用偶数张
d=work(p);
if(d!=-1)
{
if(ans==-1)ans=d;
else ans=min(ans,d);
}
///50用奇数张
if(p>=50&&num[4]>0)
{
num[4]--;
d=work(p-50);
num[4]++;
if(d!=-1)
{
if(ans==-1)ans=d+1;
else ans=min(ans,d+1);
}
}
///500用奇数张
if(p>=500&&num[7]>0)
{
num[7]--;
d=work(p-500);
num[7]++;
if(d!=-1)
{
if(ans==-1)ans=d+1;
else ans=min(ans,d+1);
}
}
///50,500都用奇数张
if(p>=550&&num[4]>0&&num[7]>0)
{
num[4]--;
num[7]--;
d=work(p-550);
num[4]++;
num[7]++;
if(d!=-1)
{
if(ans==-1)ans=d+2;
else ans=min(ans,d+2);
}
}
if(ans==-1)printf("-1\n");
else printf("%lld\n",ret-ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: