硬币找钱问题

Problem Description

设有六种不同面值的硬币,各硬币的面值分别为 5分,1角,2角,5角,1元,2元。现要用这些面值的硬币来购物和找钱。购物时可以使用的各面值的硬币个数存于数组 C o i n [ 1 ; 6 ] Coin[1;6] Coin[1;6] 中,商店里各面值的硬币有足够多。在一次购物中希望使用最少的硬币个数。

例如,一次购物需要付款 0.55 元,没有 5 角的硬币,只好用 2 × 20 + 10 + 5 2 \times 20+10+5 2×20+10+5 共 4 枚硬币来付款。如果付出 1 元,找回 4 角 5 分,同样需要 4 枚硬币。但是如果付出 1.05 元(1枚1元和1枚5分),找回 5 角,只需要 3 枚硬币,这个方案用的硬币个数最少。

对于给定的各种面值的硬币个数和付款金额,编程计算使用硬币个数最少的交易方案,如果顾客手中的硬币总量不够付款金额,则输出impossible

Sample Input

文件input.txt给出输入数据。每一行有6个整数和一个有2位小数的实数,分别表示可以使用的各种面值的硬币个数和付款金额。

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

Sample Output

输出文件 output.txt

2
3
impossible


算法源代码

#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;int Coins[6];                                      // 各面值硬币数
int CoinNum = 0;                                  // 需要的最少硬币数
int Pay;                                           // 需要支付的钱数
int CoinValue[6] = {5, 10, 20, 50, 100, 200};     // 硬币面值,以分为单位
int ChangeValue[7] = {0, 5, 10, 20, 50, 100, 200}; // 用来找零的硬币面值,0为不找零的情况
int RealMoney = CoinValue[0] - ChangeValue[0];    // 实际支付金额 = 支付硬币 - 找零硬币 【贪心变量】
ifstream input("input.txt");
ofstream output("output.txt");/*****************************************************************
* 函数描述: 从文件中读取测试数据
*****************************************************************/
void getData()
{for (int i = 0; i < 6; ++i)input >> Coins[i];double costt;input >> costt;cout << "\n目标金额:" << costt << "元"<< "\n各币值数量:" << endl;Pay = (int)(costt * 100); //将输入的钱转为分为单位for (int i = 0; i < 6; ++i)cout << Coins[i] << " ";
}/*****************************************************************
* 函数描述: 格式化输出结果
*****************************************************************/
void outputResult()
{if (CoinNum == 0 || Pay != 0){cout << "\n============== impossible" << endl;output << "impossible" << endl;}else{cout << endl<< "各币值剩余数量:" << endl;for (int i = 0; i < 6; i++)cout << Coins[i] << " ";cout << endl<< "============== 支付和找零需要的最少总硬币数量:" << CoinNum << endl;output << CoinNum << endl;}
}/*****************************************************************
* 函数描述:查看顾客手中是否还有 a 面值的硬币,
*          如果有则返回面值索引,否则返回 -1
* 函数返回:面值索引 or -1
*****************************************************************/
int contains(int a)
{for (int i = 0; i < 6; ++i)if (CoinValue[i] == a && Coins[i] > 0)return i;return -1;
}/*****************************************************************
* 函数描述: 贪心法实现硬币找零问题,以实际支付金额作为贪心变量
*****************************************************************/
void Greed()
{// 顾客手中的硬币面值从大到小遍历选取for (int i = 5; i >= 0; --i){if (Coins[i] > 0) // 如果顾客手中当前面值硬币有剩余{// 商家手中的硬币从小到大遍历选取,进行找零操作for (int j = 0; j <= i; ++j){RealMoney = CoinValue[i] - ChangeValue[j]; // 实际支付金额 = 支付硬币 - 找零硬币// 只有当实际支付金额小于目标金额的时候才进行选取,否则需要增加找零硬币的金额(即,继续本层循环 j)if (Pay >= RealMoney){if (Coins[i] >= Pay / RealMoney) //如果当前面值硬币找零后足够支付余额{int TempCoinNum = Pay / RealMoney; // 此步骤顾客消耗硬币数量CoinNum += TempCoinNum * 2;// 如果顾客具有该硬币,则无需使用找零,因为找零需要耗费2个硬币,而支付只需要一个硬币if (contains(RealMoney) != -1){TempCoinNum = min(TempCoinNum, Coins[contains(RealMoney)]);CoinNum -= TempCoinNum;Coins[contains(RealMoney)] -= TempCoinNum; // 顾客手中相应硬币数减少}elseCoins[i] -= Pay / RealMoney; // 顾客手中当前面值硬币数减少Pay = Pay % RealMoney;           // 更新还需支付的金额if (contains(CoinValue[i]) == -1)break; // 如果顾客手中该硬币用完,直接用下一个小面值}else // 如果当前币值不够支付,则用完该币值{CoinNum += Coins[i];Pay = Pay - CoinValue[i] * Coins[i];Coins[i] = 0;}}}}}
}int main()
{while (!input.eof()){CoinNum = 0;getData();       // 读取测试数据Greed();       // 贪心法实现硬币找零问题outputResult(); // 输出结果}input.close();output.close();
}

程序运行截图



贪心算法

所谓贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。

贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性。


核心思路

解决本问题在于贪心变量的找取。原始的硬币问题的贪心变量很直观,就是硬币从大到小选取(原始硬币问题的描述与解决见此链接)。而加上了找零的操作后,贪心变量就不那么直观了。本问题中的贪心变量是每个硬币的实际支付金额,加上找零的本质就是通过找零的排列组合,将硬币的面值变多了。

实 际 支 付 金 额 = 支 付 硬 币 − 找 零 硬 币 实际支付金额 = 支付硬币 - 找零硬币 实际支付金额=支付硬币−找零硬币

注意的“坑”

其中有一点需要注意的就是,如果找零的排列组合(当前硬币的实际支付金额)存在等面值的真实硬币,则不用找零的操作,直接取硬币,因为找零需要耗费 2 枚硬币,而支付只需要一枚硬币。


博主为学生,正在学习,如博文内容有误,欢迎大家在评论区更正,共同进步~

算法分析与设计:贪心算法实现最少硬币找钱问题(支付+找零共花费硬币数最少)相关推荐

  1. Suzy想吃烤蛋挞了Day35 | 贪心算法进行时:860. 柠檬水找零,406. 根据身高重建队列,452. 用最少数量的箭引爆气球

    860. 柠檬水找零 solution 不要漏掉的一种情况是:如果收到了20,可以找10+5,或者5+5+5 class Solution:def lemonadeChange(self, bills ...

  2. 贪心算法简单实践 -- 分糖果、钱币找零、最多区间覆盖、哈夫曼编解码

    1. 贪心算法概览 贪心算法是一种算法思想.希望能够满足限制的情况下将期望值最大化.比如:Huffman编码,Dijkstra单源最短路径问题,Kruskal最小生成树 等问题都希望满足限制的情况下用 ...

  3. 算法分析与设计 —— 贪心算法「活动安排」「背包问题」「哈夫曼编码」

  4. python计算n阶乘中尾部零的个数_(Java)设计一个算法,计算出n阶乘中尾部零的个数...

    展开全部 long 类型对大数阶乘来e68a8462616964757a686964616f31333365633963说存储范围大小,强行使用会溢出,可以使用 BigDecimal. 代码如下:im ...

  5. 【等价类划分法】某商店的货品价格(P)都不大于 20 元(且为整数),假设顾客每次付款为 20 元且每次限购一件商品,现有一个软件能在每位顾客购物后给出找零钱的最佳组合(找给顾客货币张数最少)。

    题目: [说明] 某商店的货品价格(P)都不大于 20 元(且为整数),假设顾客每次付款为 20 元且每次限购一件商品,现有一个软件能在每位顾客购物后给出找零钱的最佳组合(找给顾客货币张数最少). 假 ...

  6. 最少圆覆盖通信覆盖问题-算法分析设计-贪心算法-java实现

    问题描述 假设海岸线是一条无限延伸的直线,陆地在海岸线的一侧,海洋在另外一侧.每个小岛相当于海洋侧的一个点.坐落在海岸线上的基站只能覆盖半径为d的范围.应用直角坐标系,将海岸线作为x轴,设海洋侧在x轴 ...

  7. 给定k个排好序的序列,设计一个算法确定2路合并次序,使所需的总比较次数最少。Java代码

    算法分析与设计作业 一.实验目的 (1)掌握贪心算法的基本思想: (2)能使用贪心算法求解一些相关问题: 二.实验内容 1.给定k个排好序的序列s1,s2,-,sk,用2路合并算法将这k个序列合并成一 ...

  8. 算法分析与设计——贪心法实验报告

       算法导论  课程设计 成 绩 题    目:    贪心法 学院班级:        1613013         学    号:      16130130216       姓    名: ...

  9. 硬币找钱问题,求所有可能解决方案数目,最少的钱币数目,每种钱币用多少张

    [题目简介] 现存在一堆面值为 V1.V2.V3 - 个单位的硬币,一共有多少种找钱方法可以找出总值为 T 个单位的零钱?最少需要多少张钱币?在最少钱币数目找钱的条件下,每种钱币使用的次数是多少?假设 ...

最新文章

  1. python 客户端应用程序_创建python Web服务和C#客户端应用程序的最佳方法 - c#
  2. 快速解码base64和utf-8的ASCII编码和URL解码
  3. SpringCloud(三) Eureka之服务注册发现以及实现工程间调用
  4. samba服务器_win10 更新导致无法连接samba服务器
  5. java 矩阵题目_java练习本(20190611)
  6. TensorFlow2实现空间自适应归一化(Spatial Adaptive Normalization, SPADE)
  7. 《为自己工作——世界顶级设计师成功法则》—第1章1.2节有同情心
  8. 2.微信小程序(colorUI)- 构建底部操作条
  9. 链接Linux工具(SecureCRT)
  10. 手把手带你撸一个校园APP(一):项目简介
  11. 免费在线pdf转word
  12. 33岁,工作10年的老测试员被裁,所谓经验根本不值钱
  13. 计算机协会宣传部长的英语,升达浪潮计算机协会
  14. DevOps有“政治倾向性”
  15. asp.nett网站发布过程
  16. pytorch和tensorflow中实现SMU激活函数
  17. 甲虫之王怀旧服新开的服务器是否自动开门,魔兽世界怀旧服:千人转到未开门服务器,会诞生千只甲虫之王吗?...
  18. M1卡 S50与S70的区别
  19. vba 定义类_使用WithEvents定义响应事件的对象
  20. Windows server 2016 学习 一

热门文章

  1. 跨平台AR增强现实开发(一)(AR开发环境的搭建)
  2. ECMAScript6(7):二进制数组
  3. 【前端知识之JS】BOM的理解
  4. conhosts 占用CPU
  5. 使用sql如何找出两张表中同一字段的不同值
  6. mysql5.5 mysql5.6 mysql5.7官方手册
  7. 读取绘制visio文件
  8. 图像多功能实时智能处理产品——西安恒景通视觉科技有限公司
  9. 弹性云服务器的规格系列,新睿云简析云服务器的配置规格怎么选择?
  10. 【日记本砸】21.04.01-15 上生活的贼船,做快乐的海盗