#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; // 顾客手中相应硬币数减少
}
else
Coins[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();
}