HDU 5527

硬币找零问题的贪心算法解析
本文深入探讨了一道经典的贪心算法题目——硬币找零问题,通过枚举特殊情况和优化计算策略,详细讲解了如何求解硬币的最小数量,以及在特定条件下如何处理无解的情况。

这是一道贪心的题目

首先要注意的是计算最多硬币数及逆向计算留下的钱的最少硬币数

还有要枚举50和500这两个例外的奇偶性

调试时要注意

  1 既然已经枚举了,取的时候一定要取偶数个

  2 计算总数量的时候一定要加上自己已经取得数目

  3 int 和long long不影响本题的结果

  4 枚举的时候一定要判断能否取出一枚50或500的硬币

  5 可能有一些枚举情况无解,这时要返回inf

  6 即使在取出钱数小于等于总钱数的情况下,也会有无解,这时一定要判断

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=999999999;
inline int read(){
	int x=0,f=1,ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline int min(int x,int y){
	return x<y?x:y;
}
int a[10];
int id[10]={1,5,10,20,50,100,200,500,1000,2000};
int flag;
inline int cal(int x){
	int res=0;
	for(int i=9;i>=0;i--){
		int num=min(a[i],x/id[i]);
		x-=num*id[i];
		if(i==4||i==7) num<<=1;
		res+=num;
	}
	if(x) return inf;
	return res;
}
int main(){
	int T=read();
	while(T--){
		int p=read(),sum=0,cnt=0;
		for(int i=0;i<10;i++) a[i]=read(),sum+=a[i]*id[i],cnt+=a[i];
		if(p>sum){
			puts("-1");
			continue;
		}
		if(p==sum){
			printf("%d\n",cnt);
			continue;
		}
		// cout<<id[4]<<"\t"<<id[7]<<endl;
		p=sum-p;id[4]=100;id[7]=1000;
		// cout<<p<<endl;
		int ans,num1,num2;
		num1=a[4];num2=a[7];a[4]>>=1;a[7]>>=1;
		ans=cal(p);
		a[4]=num1;a[7]=num2;
		if(p>=50&&a[4]){
			p-=50;a[4]--;
			num1=a[4];num2=a[7];a[4]>>=1;a[7]>>=1;
			ans=min(ans,cal(p)+1);
			a[4]=num1;a[7]=num2;
			p+=50;a[4]++;
		}
		if(p>=500&&a[7]){
			p-=500;a[7]--;
			num1=a[4];num2=a[7];a[4]>>=1;a[7]>>=1;
			ans=min(ans,cal(p)+1);
			a[4]=num1;a[7]=num2;
			p+=500;a[7]++;
		}
		if(p>=550&&a[4]&&a[7]){
			p-=550;a[4]--;a[7]--;
			a[4]>>=1;a[7]>>=1;
			ans=min(ans,cal(p)+2);
		}
		id[4]=50;id[7]=500;
		if(ans==inf) puts("-1");
		else printf("%d\n",cnt-ans);
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/gcyyzf/p/9695737.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值