7-7 硬币找钱问题 (10 分)(思路+详解+double类型数据的处理)Come baby!!!!!!!!!!!!!!!!!!!!

一:题目

设有6 种不同面值的硬币,各硬币的面值分别为5 分,1 角,2 角,5 角,1 元,2元。现要用这些面值的硬币来购物。在购物中希望使用最少个数硬币。例如,1 次购物需要付款0.55 元,如果没有5 角的硬币,只好用22角+11角+1*5分 共4 枚硬币来付款。

对于给定的各种面值的硬币个数和付款金额,计算使用硬币个数最少的交易方案。

输入格式:
输入数据有若干组,第一行给出一个整数n表示输入数据的组数。

以下n行每一行有6 个整数和1个有2 位小数的实数。分别表示可以使用的各种面值的硬币个数和付款金额。

输出格式:
输出每组数据的最少硬币个数。如果不可能完成交易,则输出“impossible”。

输入样例:

2
2 4 2 2 1 0 0.95
2 4 2 0 1 0 0.55

输出样例:

4
4

二:思路

思路:
1.map容器进行存储 键值为面值(0.05,0.1,0.2,0.5,1,2) 关键值为对应的硬币个数
2.将付款金额跟面值进行比较,找到刚好大于其面值的银币,并判断其个数是否有无,
1>:如果其个数为0就继续往下寻找银币,直到银币个数不为0为止
2>:如果其个数不为0的话那么我们就选择 小于 付款金额的 银币数 并记录个数
付款金额 = 付款金额 - 面值*银币数;

当付款金额小于面值的时候继续往下寻找更小的面值
当银币数不够了也是往下继续寻找最小隐蔽数

3.如果最后的付款金额不为0,那么就是 impossible

测试数据:2
2 4 2 2 1 0 0.95
2 4 2 0 1 0 0.55

4.注意处理数据中的小数问题,因为double 存的数据和真实的并不一样
eg :比如存入的是0.95 其实是0.9499999999182,那么当数据剩下0.0499909
那么它和0.05就无法比较了

三:关于处理double类型数据的精度问题

1.问题展示

问题描述:我们明明输入的是double类型的 0.95 但通过调试我们发现其实他是 0.949999999,
在这里插入图片描述

2.回归本题

本题但这中的测试用例1中有0.95这个付款金额,那么我们选择银币的时候,会选择一个 0.5,两个0.2,那么还剩0.05,
剩下0.05是我们希望的正常情况,但是通过上方的演示,我们发现其是真实的值是小于0.05的,那么这样的话就会影响我们计算银币的个数,因为统计不到0.05的银币个数

3.解决问题

本题当中自我感觉很开窍的地方,我们给付款金额加上0.00001,这样就能保证我的数据最起码是大于面值的,最后的余额再跟0.00001比较,如果小于其就是可以完全换成金币个数的。注意这里不能是等于0.00001,因为确实是两个数不相等,而且即便你将调试显示的数抄上去都不行!!!

四:上码

	/**
	   思路:1.map容器进行存储 键值为面值(0.05,0.1,0.2,0.5,1,2) 关键值为对应的硬币个数
	   		 2.将付款金额跟面值进行比较,找到刚好大于其面值的银币,并判断其个数是否有无,
				1>:如果其个数为0就继续往下寻找银币,直到银币个数不为0为止
				2>:如果其个数不为0的话那么我们就选择 小于 付款金额的 银币数 并记录个数 
				   付款金额 = 付款金额 - 面值*银币数;
				   
				   当付款金额小于面值的时候继续往下寻找更小的面值
				   当银币数不够了也是往下继续寻找最小隐蔽数
				   
			3.如果最后的付款金额不为0,那么就是	impossible			    
				     
				
				测试数据:2
						2 4 2 2 1 0 0.95
						2 4 2 0 1 0 0.55 
						
			4.注意处理数据中的小数问题,因为double 存的数据和真实的并不一样
				eg :比如存入的是0.95 其实是0.9499999999182,那么当数据剩下0.0499909
					那么它和0.05就无法比较了		
	    
	*/
	
	
	#include<bits/stdc++.h>
	using namespace std;
	
	int res(vector<double>& v){
		
		map<double,double>m;
		map<double,double>:: reverse_iterator t;
		int length = v.size();
		float pay = 0.00001; //付款金额 
		int cnt = 0;//统计银币个数       
		
		for(int i = length - 1; i >= 0; i--){
			if(i == 0) m[0.05] = v[i];
			if(i == 1) m[0.1] = v[i];
			if(i == 2) m[0.2] = v[i];
			if(i == 3) m[0.5] = v[i];
			if(i == 4) m[1] = v[i];
			if(i == 5) m[2] = v[i];   
			if(i == 6) pay += v[i];
		}
		
		for(t = m.rbegin(); t != m.rend(); t++){
			
			if(pay >= t->first && t->second != 0){//如果付款金额大于其面值 并且该面值银币数不为0 
			
				for(int i = 0; i < t->second; i++){
					
					   if(pay >= t->first){//这里确保每次的付款金额均大于面值 
					   		pay = pay - t->first;
					   		cnt++; 
						}else{
							break;
						}
				}
				 
			}	
		}
		//cout << cnt;
	//	cout << pay << endl;
	//0.00999999139	
		if(pay <= 0.001){
			return cnt;
	//	cout << "wyj";
		}
		
		return -1;	
	}
	
	int main(){
		
		int n;
		cin >> n;
		
		for(int i = 0; i < n; i++){
			
			vector<double>v;
			
			for(int i = 0; i < 7; i++){
				double nums;
				cin >> nums;
				v.push_back(nums);
			}
			
			int ans = res(v);
			
			if(ans == -1){
				cout << "impossible" << endl;
			}else{
				cout << ans << endl;
			}
				
		}	
	} 
	
	
	//2
	//2 4 2 2 1 0 0.95
	//2 4 2 0 1 0 0.55
	//
	//
	//1
	//2 4 2 2 1 0 0.95
	
	
	//1
	//2 4 2 2 1 0 0.05
	
	//
	//1
	//2 4 2 2 1 0 0.95
	

在这里插入图片描述

五:知识速递(如果对map容器不熟悉的兄弟们可以了解下)

map的逆序遍历
map的基本用法

又得唠叨一句 记得加油 宝!!!!!!!!!!!!!!!!!!!

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天向上的菜鸡杰!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值