动态规划入门之硬币问题
2016-09-13 00:00
183 查看
摘要: 动态规划入门之硬币问题
动态规划算法通常基于一个递推公式及一个或多个初始状态。 当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度, 因此它比回溯法、暴力法等要快许多。动态规划也是面试笔试题中的一个考查重点,当阅读一个题目并且开始尝试解决它时,首先看一下它的限制。 如果要求在多项式时间内解决,那么该问题就很可能要用DP来解。遇到这种情况, 最重要的就是找到问题的“状态”和“状态转移方程”。(状态不是随便定义的, 一般定义完状态,你要找到当前状态是如何从前面的状态得到的, 即找到状态转移方程)如果看起来是个DP问题,但你却无法定义出状态, 那么试着将问题规约到一个已知的DP问题。
这里先说明一个最简单的动态规划实例:硬币问题。后续还会给出更多的实例,例如:最长公共子序列,最长公共子串,最长递增子序列,字符串编辑距离等。动态规划的关键就是找出“状态”和“状态转移方程”。
硬币问题:给你一些面额的硬币,然后给你一个值N,要你求出构成N所需要的最少硬币的数量和方案。分析:这个问题可以尝试用贪心算法去解决,先从面额最大的硬币开始尝试,一直往下找,知道硬币总和为N。但是贪心算法不能保证能够找出解(例如,给,2,3,5,然后N=11)。我们可以换个思路,我们用d(i)表示求总和为i的最少硬币数量(其实就是动态规划中的“状态”),那么怎么从前面的状态(并不一定是d(i-1)这一个状态)到d(i)这个状态?假设硬币集合为coins[0~N],在求d(i)之前,我们假设d(1~i-1)全部都求出来了,那么d(i)=min{d(j)+1},if i-j 在coins中(其实这就是“状态转移方程”)。举例说明:coins={2,3,5},N=11。
d(0)=0;
d(1)=0;
d(2)=d(0)+1=1;
d(3)=d(0)+1=1;
d(4)=d(2)+1=2;
d(5)=min{d(3)+1,d(2)+1,d(0)+1}=1;
d(6)=min{d(4)+1,d(3)+1}=2;
.......................
同时为了求出最后的方案(不仅仅是硬币个数),需要记录求每个状态选择的“路径”,例如:求d(5)我们选择了d(0)+1,那么我们选择的路径就是5-0=5。我们必须记录这些路径,然后根据路径得出结果。对于d(6),我们开始选择了3,也就是说我们选择了从d(3)状态和硬币3跳转到d(6),接着对于d(3),我们选择了3,也就是说我们选择了从d(0)状态和硬币3跳转到了d(3),接着对于d(0),这个是初始状态。所以我们的方案是3,3。
如果上面说得还不够清晰,可以参照下面JAVA实现的代码
动态规划算法通常基于一个递推公式及一个或多个初始状态。 当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度, 因此它比回溯法、暴力法等要快许多。动态规划也是面试笔试题中的一个考查重点,当阅读一个题目并且开始尝试解决它时,首先看一下它的限制。 如果要求在多项式时间内解决,那么该问题就很可能要用DP来解。遇到这种情况, 最重要的就是找到问题的“状态”和“状态转移方程”。(状态不是随便定义的, 一般定义完状态,你要找到当前状态是如何从前面的状态得到的, 即找到状态转移方程)如果看起来是个DP问题,但你却无法定义出状态, 那么试着将问题规约到一个已知的DP问题。
这里先说明一个最简单的动态规划实例:硬币问题。后续还会给出更多的实例,例如:最长公共子序列,最长公共子串,最长递增子序列,字符串编辑距离等。动态规划的关键就是找出“状态”和“状态转移方程”。
硬币问题:给你一些面额的硬币,然后给你一个值N,要你求出构成N所需要的最少硬币的数量和方案。分析:这个问题可以尝试用贪心算法去解决,先从面额最大的硬币开始尝试,一直往下找,知道硬币总和为N。但是贪心算法不能保证能够找出解(例如,给,2,3,5,然后N=11)。我们可以换个思路,我们用d(i)表示求总和为i的最少硬币数量(其实就是动态规划中的“状态”),那么怎么从前面的状态(并不一定是d(i-1)这一个状态)到d(i)这个状态?假设硬币集合为coins[0~N],在求d(i)之前,我们假设d(1~i-1)全部都求出来了,那么d(i)=min{d(j)+1},if i-j 在coins中(其实这就是“状态转移方程”)。举例说明:coins={2,3,5},N=11。
d(0)=0;
d(1)=0;
d(2)=d(0)+1=1;
d(3)=d(0)+1=1;
d(4)=d(2)+1=2;
d(5)=min{d(3)+1,d(2)+1,d(0)+1}=1;
d(6)=min{d(4)+1,d(3)+1}=2;
.......................
同时为了求出最后的方案(不仅仅是硬币个数),需要记录求每个状态选择的“路径”,例如:求d(5)我们选择了d(0)+1,那么我们选择的路径就是5-0=5。我们必须记录这些路径,然后根据路径得出结果。对于d(6),我们开始选择了3,也就是说我们选择了从d(3)状态和硬币3跳转到d(6),接着对于d(3),我们选择了3,也就是说我们选择了从d(0)状态和硬币3跳转到了d(3),接着对于d(0),这个是初始状态。所以我们的方案是3,3。
如果上面说得还不够清晰,可以参照下面JAVA实现的代码
/** * * @author kerry * 给定制定面值的硬币 ,并给出一个值,要求求出硬币综合为这个值需要的最少的硬币的个数,并具体的方案 */ public class MinCoins { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] coins={1,3,5}; int value=100; int[] solu=new int[value]; int min=new MinCoins().solution(coins,value,solu); for(int i=value-1;i>=0;){ System.out.print(solu[i]+"->"); i=i-solu[i]; } System.out.println(); System.out.println(min); } private int solution(int[] coins,int value, int[] solu){ int[] mins = new int[value+1]; mins[0]=0; for(int i=1;i<=value;i++) mins[i]=Integer.MAX_VALUE; for(int i=1;i<=value;i++){ for(int j=0;j<coins.length;j++){ if(coins[j]<=i&&mins[i]>mins[i-coins[j]]+1){ mins[i]=mins[i-coins[j]]+1; solu[i-1]=coins[j]; } } } return mins[value]; } }
相关文章推荐
- 动态规划入门之硬币找零问题
- 动态规划入门之硬币问题(转)
- 0-1背包问题入门小结 动态规划(DP)经典题目 POJ324 POJ1276
- 入门硬币问题
- 动态规划入门之硬币问题
- 动态规划只11硬币的问题
- 0-1背包问题入门小结 动态规划(DP)经典题目 POJ324 POJ1276
- 硬币找零问题_动态规划_算法与数据结构
- 动态规划之硬币组合问题
- wikioi天梯之1014 装箱问题 入门动态规划 【背包问题】
- 硬币找零问题 - 动态规划
- 硬币找零问题(动态规划)
- 算法导论 动态规划入门之装配线调度问题
- 硬币问题之记忆化搜索-动态规划 By ACReaper
- 动态规划求解硬币找零问题——Java实现
- 由硬币问题和邮票问题看动态规划
- 最少硬币问题(动态规划解决)
- 动态规划解投硬币的概率问题
- 算法竞赛入门经典 例题9-3 硬币问题
- 硬币组合问题-动态规划