最少硬币找零问题

Problem:

Give you the coins, and the total amount of money to change,find a solution for this change which minimize the number of coins needed.

Example:

Coins[] = {1,3,9,10};

Money = 15

Solution[] = {3,3,9}

分析:这道题类似于背包问题,背包问题的思路是,考虑第j个物品装入容量为j的背包中,此时有两只情况,j装得进去,j装不进去,然后推到出动态规划状态转移方程。对于这个问题,我们也可以用相同的思路来思考。

归纳(第一次尝试):假设已知如何解决money为i-1,硬币种类为j-1的子问题,记为P(i-1,j-1)。

接下来怎么办呢,如何推到出P(i,j)?在这样的归纳基础下面,我们不得不从i-1,j-1归纳出i,j来,也就是说我们在这个过程中同时对两个变量进行了归纳,这样会导致问题变得有些复杂,无从下手。(心得:如果在某一处卡住了,回头看看这个过程是否有漏洞;其次在读读题目,看看是否漏掉一些信息,题目的最终结果是求什么,怎么来表示这个结果。)

归纳(第二次尝试):假设已知如何解决P(i,j-1)。这个归纳就比上面那个好一些,而且容易思考下一步的问题,因为现在我们只要考虑第j种硬币,从而看看能否推导出P(i,j)。对于第j中硬币,我们有两种策略,一是使用第j种硬币不能使当前结果更优;二是使用第j种硬币能使当前结果更优,下面重点分析第二种情况。

现在问题变为要使用第j种硬币,那么该用多少呢?记Cj= i/j,这是单独使用第j种硬币需要的数量,Vj表示j的面值。接取Cj是最优的吗?怎样证明这样不行?

设Rj = i-Cj*Vj,使用Cj后剩余的money;设Qj= i-(Cj-1)*Vj, 使用Cj-1个硬币后剩余的money此时Qj = Rj + Vj。那么接下来找零Rj使用的硬币一定比找零Qj的硬币少吗?这个不一定,因为Rj相比Qj跟小,这个意味着需要更多的零钱。比如Rj=2,Qj=12,此时都需要两个硬币(1,1和3,9),而最终结果是开始选择Cj-1比选择Cj的少一个。所以在这里,应当全面的考察由1,2,…Cj的情况。

P(i,j-1)=MIN{ P(i,j-1),P(i-k*Vj,j-1)+k}(k=1,2,…Cj)


参考代码:

有些动态规划的中间结果不需要多维数组来存放,有些情况只需要一维数组即可,知道如何写和自己动手写出来,得到的信息不一样,唯有动手才能体会更多

int leastnums(int coins[], int numcoin,int money)
{
	if(numcoin < 1 || money < 0 || coins[0] > money)
		return -1;

	int *res = new int[money+1];

	//初始化,只用第一个硬币
	for(int i = 1; i < money+1; ++i)
		res[i] = money / coins[0];

	for(int j = 1; j < numcoin; ++j)
	{
		for( int i = coins[j]; i < money+1; ++i)
		{
			int k = i / coins[j];
			if( i%coins[j]==0)
			{
				res[i] = k;
				continue;
			}
			while(k)
			{
				int left = i - k*coins[j];
				if(res[left]+k < res[i])
					res[i] = res[left]+k;
				--k;
			}
		}//end for
	}//end for

	return res[money];
}

int _tmain(int argc, _TCHAR* argv[])
{
	int coins[]={1,3,9,10};
	int lnum = leastnums(coins,4,22);
	return 0;
}

总结:动态规划还可以在优化吗?动态规划有一个变形,叫备忘录法。备忘录法也是用一个表格来保存已解决的子问题的答案,并通过记忆化搜索来避免计算一些不可能到达的状态。其实在写动态规划code过程中,有些地方也可以进行改进和优化,并非没一个动态规划都可以优化。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
最少硬币找零问题是动态规划领域中的一个经典问题,其主要思想是使用动态规划算法来求解最少硬币数量,以凑出给定的金额。 该问题可以用动态规划的思想来求解,具体思路如下: 1. 定义状态:用 dp[i] 表示凑出 i 元所需要的最少硬币数量。 2. 状态转移方程:对于每个硬币的面值,我们可以选择使用该硬币或者不使用该硬币,因此可以得到状态转移方程:dp[i] = min(dp[i], dp[i - coins[j]] + 1),其中 coins[j] 表示第 j 枚硬币的面值,dp[i - coins[j]] 表示使用该硬币所需的最少硬币数量。 3. 边界条件:当需要凑出的金额为 0 时,所需的最少硬币数量为 0,即 dp[0] = 0。 4. 最终结果:最终结果为 dp[amount],其中 amount 为需要凑出的金额。 下面给出一个动态规划实现最少硬币找零问题的 Python 代码: ```python def coinChange(coins, amount): dp = [float('inf')] * (amount + 1) dp[0] = 0 for i in range(1, amount + 1): for j in range(len(coins)): if coins[j] <= i: dp[i] = min(dp[i], dp[i - coins[j]] + 1) return dp[amount] if dp[amount] != float('inf') else -1 ``` 该函数接受两个参数,一个是硬币数组 coins,另一个是需要凑成的金额 amount。最终返回凑成 amount 元所需的最少硬币数,如果无法凑成则返回 -1。 接下来对该算法进行分析讨论。 1. 时间复杂度分析 该算法使用了两层循环,因此时间复杂度为 O(amount * len(coins))。 2. 空间复杂度分析 该算法使用了一个数组 dp 来存储状态值,因此空间复杂度为 O(amount)。 3. 实验结果分析 下面对该算法在不同数据集上的实验结果进行分析。 (1)coins = [1, 2, 5],amount = 11 该数据集中包含了三种不同面值的硬币,需要凑出的金额为 11。使用该算法可以得到最少硬币数量为 3。 (2)coins = [2],amount = 3 该数据集中只包含了一种面值为 2 的硬币,需要凑出的金额为 3。使用该算法可以得到无法凑成该金额的结果 -1。 (3)coins = [1, 3, 4],amount = 6 该数据集中包含了三种不同面值的硬币,需要凑出的金额为 6。使用该算法可以得到最少硬币数量为 2。 从以上实验结果可以看出,该算法具有较好的准确性和实用性,能够在不同的数据集上得到较好的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值