最少硬币找零问题-动态规划

动态规划把问题分为子为题,解决了这些子问题,再把子问题合并起来,便可以得到问题的解。在解决子问题过程中,需要把子问题的解保存起来方便后面使用。

最少硬币找零问题为:给予不同面值的硬币若干种种(每种硬币个数无限多),用若干种硬币组合为某种面额的钱,使硬币的的个数最少。

在现实生活中,我们往往使用的是贪心算法,比如找零时需要13元,我们先找10元,再找2元,再找1元。这是因为现实生活中的硬币(纸币)种类特殊。如果我们的零钱可用的有1、2、5、9、10。我们找零18元时,贪心算法的策略是:10+5+2+1,四种,但是明明可以用两个9元的啊。

所以可以使用动态规划,找零18元时,我们首先找18-1=17,18-2=15,18-5,=13,18-9,=9,18-10=8;再找17-1……。这样递归解决子问题

#include<iostream>
using namespace std;
//money需要找零的钱
//coin可用的硬币
//硬币种类
void FindMin(int money,int *coin, int n)
{
	int *coinNum=new int[money+1]();//存储1...money找零最少需要的硬币的个数
	int *coinValue=new int[money+1]();//最后加入的硬币,方便后面输出是哪几个硬币
	coinNum[0]=0;

	for(int i=1;i<=money;i++)
	{
		int minNum=i;//i面值钱,需要最少硬币个数
		int usedMoney=0;//这次找零,在原来的基础上需要的硬币
		for(int j=0;j<n;j++)
		{
			if(i>=coin[j])//找零的钱大于这个硬币的面值
			{
				//if(coinNum[i-coin[j]]+1<=minNum)//所需硬币个数减少了
				/*
				上面的判断语句有问题,在更新时,需要判断i-coin[j]是否能找的开,如果找不开,就不需要更新。
				多谢zywscq 指正
				*/
				if(coinNum[i-coin[j]]+1<=minNum&&(i==coin[j]||coinValue[i-coin[j]]!=0))//所需硬币个数减少了
				{
					minNum=coinNum[i-coin[j]]+1;//更新
					usedMoney=coin[j];//更新
				}
			}
		}
		coinNum[i]=minNum;
		coinValue[i]=usedMoney;
	}

	//输出结果
	if(coinValue[money]==0)
		cout<<"找不开零钱"<<endl;
	else
	{
		cout<<"需要最少硬币个数为:"<<coinNum[money]<<endl;
		cout<<"硬币分别为:";
		while(money>0)
		{
			cout<<coinValue[money]<<",";
			money-=coinValue[money];
		}
	}
	delete []coinNum;
	delete []coinValue;
}
int main()
{
	int Money=18;
	int coin[]={1,2,5,9,10};
	FindMin(Money,coin,5);

}


  • 17
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
好的,我会尽力为您解答。首先,让我们来了解一下凑硬币问题。 在凑硬币问题中,我们需要找到最少硬币数来凑成给定的金额。例如,如果我们需要凑成 11 元,而有 1 元、2 元、5 元三种不同面值的硬币可供使用,那么最少需要使用 3 枚硬币,即 5 元、5 元和 1 元。 下面是一种使用动态规划解决凑硬币问题的方法: 1. 创建一个长度为 amount+1 的数组 dp,其中 dp[i] 表示凑成面值为 i 元所需的最少硬币数。 2. 初始化 dp[0] 为 0,其余元素初始化为一个较大的数(例如 amount+1),表示当前面值无法被凑成。 3. 遍历硬币数组 coins,对于每个硬币,遍历 dp 数组,更新 dp[j] 的值为 dp[j-coins[i]]+1,其中 j>=coins[i],表示当前面值可以被凑成。 4. 最终 dp[amount] 就是凑成 amount 元所需的最少硬币数,如果 dp[amount]>amount,则表示无法凑成给定金额。 下面是使用 JavaScript 实现该算法的代码: ```javascript function coinChange(coins, amount) { const dp = new Array(amount + 1).fill(amount + 1); dp[0] = 0; for (let i = 0; i < coins.length; i++) { for (let j = coins[i]; j <= amount; j++) { dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1); } } return dp[amount] > amount ? -1 : dp[amount]; } ``` 这个函数接受两个参数,一个是硬币数组 coins,另一个是需要凑成的金额 amount。最终返回凑成 amount 元所需的最少硬币数,如果无法凑成则返回 -1。 例如,若 coins = [1, 2, 5],amount = 11,则 coinChange(coins, amount) 的返回值为 3,表示凑成 11 元最少需要 3 枚硬币。 希望这个简单的解释和代码能够帮到您,如果您还有其他问题,请随时问我。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值