动态规划之Coin Change问题(Java,C语言实现)
2021/5/21 12:55:13
本文主要是介绍动态规划之Coin Change问题(Java,C语言实现),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
动态规划之Coin Change Fewest Number(C语言,Java实现)
一、问题定义:
You given coins of different denominations and a total amount of money amount. Find the fewest number of coins that you need to make up that amount.
具体化一下:假设你有三种硬币,面值分别为1,3,5,每种硬币有足够多,现在需要11元,求最少的硬币组合
二、问题分析
(一)问题的类型
贪心算法AND动态规划
贪心算法:把一个大问题分解成一个个子问题,希望通过局部最优解来获得全局最优解,但是不能保证给出全局最优解,而且有时候即使问题有解贪心算法给出的仍然是无解;
动态规划和贪心的区别之一在于:只要问题有解,动态规划就能够给出最优解
For instance:
1.Given:Coins={1,8,13},16cents=?
Greedy solution:4 coins:13+1+1+1
Optimal solution:2 coins:8+8
2.Given:Coins={2,8,15},24cents=?
Greedy solution:no solution:coins:15+8+?
Optimal solution:3 coins:8+8+8
所以硬币问题需要采用动态规划来解决(当然你也可以采用递归来求解,但相比之下递归求解时,重叠子问题很多,所以导致整个算法时间复杂度不太理想)
(二)动态规划求解过程
1、确定状态
(1)最后一步
虽然我们不知道最优解是什么,但是最优策略肯定是k枚硬币COIN1,COIN2,COIN3…COINk,这些硬币的面值加起来刚好等于我们需要的总金额M,所以一定有最后一枚硬币COINk,去掉这枚硬币,前面的硬币面值加起来是M-COINk
(2)子问题
我们不关心前面的k-1枚硬币是如何凑成M-COINk的,现在也不知道COINk和k具体是什么,但是k-1枚硬币凑出了M-COINk是可以确定的,因为要求最优解,所以凑成M-COINk的硬币数量也一定是最少的(不理解的可以用反证法证一下);
所以我们接下来求:用最少的硬币凑成M-COINk,原问题是最少硬币凑成M,这样一来我们就把原问题化成了一个子问题,问题的规模就缩小了,我们假设状态
f(X)=最少用多少枚硬币拼出X
接下来看那最后一枚硬币是多少?问题开始前我已经把问题具体化了(M=11,硬币面值有{1,3,5})所以这里的最后一枚硬币COINk只能是1,3,或者5;
如果COINk=1, f(11)=f(11-1)+1(加上最后一枚硬币1);
如果COINk=3, f(11)=f(11-3)+1(加上最后一枚硬币3);
如果COINk=5, f(11)=f(11-5)+1(加上最后一枚硬币5);
除此之外没有其他可能性了
需要求最少的硬币数,所以:
f(11)=min{f(11-1)+1,f(11-3)+1,f(11-5)+1}
2、转移方程
动态规划我们一般要用到数组来写状态转移方程
设状态f[X]=最少用多少枚硬币拼出X
对于任意的X,都有
f[x]=min{f[X-1]+1,f[X-3]+1,f[X-5]+1}
3、初始状态和边界条件
f[x]=min{f[X-1]+1,f[X-3]+1,f[X-5]+1}
先思考两个问题
问题1:X-1,X-3,X-5小于0的情况应该怎么办?
问题2:什么时候停下来?
解决问题:
如果拼不出来values,就定义f[values]=正无穷,如:f[-1]=f[-2]=正无穷
初始条件:f[0]=0;
计算后面的值,我们需要用到f[0],但是如果用转移方程来计算我们会得到正无穷,可是实际上f[0]=0;边界情况其实就是不要数组越界。
4.计算顺序
拼出X所需的最少硬币数:
f[x]=min{f[X-1]+1,f[X-3]+1,f[X-5]+1}
初始条件:f[0]=0;
然后计算f[1],f[2]…f[11]
当我们计算f[X]时,f[X-1],f[X-3],f[X-5]都已经得到结果了
计算顺序的确定原则:当我们用计算等式左边时,右边用到的状态都已经算过了
三、代码实现
1.Java代码(附运行结果)
public class coinChange { //{1,3,5} //M=11 public static int coin(int[] a,int M){ int [] f=new int[M+1]; int n=a.length;//number of kinds of coins //initialization f[0]=0; int i,j; //f[1],f[2]...f[11] for(i=1;i<=M;i++) { f[i]=Integer.MAX_VALUE; //last coin a[j] //f[i]=min{f[i-a[0]]+1...f[i-a[n-1]]+1} for(j=0;j<n;++j) { if(i>=a[j] && f[i-a[j]]!=Integer.MAX_VALUE){ f[i]=Math.min(f[i-a[j]]+1,f[i]); } } } if(f[M]==Integer.MAX_VALUE){ f[M]=-1; } return f[M]; } public static void main(String[] args) { int []a={1,3,5}; int M=11; int coins_number=coin(a,M); System.out.println(coins_number); } }
运行结果
2.C语言代码(附运行结果)
#include<stdio.h> int coinChange(int* coins, int coinsSize, int values) { int* dp = (int*)calloc(values + 1, sizeof(int)); int i, j; for (i = 0; i <= values; i++) { dp[i] = values + 1;//初始化 } dp[0] = 0; for (i = 0; i <= values; i++) { for (j = 0; j < coinsSize; j++) { if (i < coins[j]) continue; dp[i] = dp[i] < dp[i - coins[j]] + 1 ? dp[i] : dp[i - coins[j]] + 1; } } return (dp[values] != values + 1) ? dp[values] : -1; } int main(void) { int coins[] = { 1,3,5 }; int coinsSize = 3; int values = 11; int num = coinChange(coins, coinsSize, values); printf("最少需要%d枚硬币\n", num); return 0; }
运行结果
结束:最近刚学的动态规划,记录一下,有不足的还请指出,大家共同进步!
这篇关于动态规划之Coin Change问题(Java,C语言实现)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南