博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 5527 贪心
阅读量:7048 次
发布时间:2019-06-28

本文共 3541 字,大约阅读时间需要 11 分钟。

Too Rich

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

Total Submission(s): 1666    Accepted Submission(s): 422

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.
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
 
听说是一个金牌题,确实很巧妙。
开始的想法是,多重背包,用二进制优化成01背包,d[i] :钱币为 i 的最多钱币数目,但是开不了这么大的数组,用map映射一下,或者改成记忆化搜索写法,但是是不可能的,记忆化还是得有一个vis数组~~~。
 
 
正解:
先转换思路,凑P求最多硬币,转为求mon - P 的最少硬币数。
然后贪心,但是会像记忆化搜索一样要回溯。直接贪心不太好。但是,硬币问题有一个特点,如果所有的钱币如: 1  ,   5   ,   10  ,   20  , 40   ,   80  ,   800,你已经看出来了,就是这种前面是后面的因子,这样就不可能说要从后往前的过程中要回溯。直接从后往前贪心。
 
怎么转为这种情况呢,发现只要改变两个数  50,500,改成 100,1000来用,就可以了。
#include 
using namespace std;const int inf = 0x3f3f3f3f;int c[30];int v[10] = {
1,5,10,20,50,100,200,500,1000,2000};int num[10];int sum,mon,p,ans;int solve(int x) { int ret = 0,need; for(int i = 9; i >=0; i--) { if(v[i]==500) { need = x/1000; need = min(need,num[i]/2); ret +=2*need; x-=need*1000; } else if(v[i]==50) { need = x/100; need = min(need,num[i]/2); ret +=2*need; x-=need*100; } else { need = x/v[i]; need = min(need,num[i]); ret +=need; x -=need*v[i]; } } if(x) return inf; return ret;}int main(){ //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--) { sum = mon = 0; scanf("%d",&p); for(int i = 0; i < 10; i++) { scanf("%d",&num[i]); sum +=num[i]; mon +=num[i]*v[i]; } p = mon - p; //最少的硬币去兑换 if(p<0) { puts("-1"); continue; } ans = inf; ans = min(ans,solve(p)); if(num[7]) { p-=500;num[7]--; if(p>=0) ans = min(ans,solve(p)+1); p+=500;num[7]++; } if(num[4]) { p-=50;num[4]--; if(p>=0) ans = min(ans,solve(p)+1); p+=50; num[4]++; } if(num[4]&&num[7]) { p-=550;num[4]--;num[7]--; if(p>=0) ans = min(ans,solve(p)+2); } if(ans==inf) puts("-1"); else printf("%d\n",sum-ans); } return 0;}
View Code

 

 

转载于:https://www.cnblogs.com/TreeDream/p/7861776.html

你可能感兴趣的文章
配置远程访问服务(×××)
查看>>
大型网站架构之分布式消息队列
查看>>
junit 在MyEclipse上怎么用?
查看>>
WebKit技术内幕
查看>>
数组应用--图片切换
查看>>
Tomcat集群通过NoSQL高速存储共享session的实例
查看>>
CentOS上安装Bugzilla 4.5.2
查看>>
这辈子最有先见之明的一个设计
查看>>
vue分页
查看>>
控件拉伸(转)
查看>>
我的友情链接
查看>>
Whats new in openstack juno
查看>>
个人网站创业一年的悲惨经历分享
查看>>
学习笔记之urllib篇
查看>>
python练习-for range if continue
查看>>
7.28_Linux_ext数据结构inode的原理浅析、软硬链接的区别
查看>>
挂号网 牛B
查看>>
如何实现一个按周递增的序列
查看>>
SAP公司联席CEO Bill McDermott先生的至理名言:“我们要保持饥饿感和谦逊的态度。”...
查看>>
openssl crl2pkcs7 使用方法
查看>>