演算法初探-動態規劃(Dynamic Programming)
阿新 • • 發佈:2019-01-22
程式設計之中接觸到很多關於演算法的知識,想來整理一番,算是對自己記憶的一個提醒
1.Coin11Problem 問題為:使用最少的三種面值為1,3,5的硬幣組合出11元。
重要的是狀態以及狀態轉移方程 d(i)=min{ d(i-vj)+1 },其中i-vj >=0,vj表示第j個硬幣的面值;
package com.njit.dynamic_programming; /** * 使用最少若干的1,3,5硬幣,組合出11元 * * @author 邵鵬 * @version [V1.00, 2017年7月13日] * @see [相關類/方法] * @since V1.00 */ public class Coin11Problem { public static void main(String[] args) { //狀態以及狀態轉移方程 //d(i) d(i)=min{d(i-vj)+1} vj為硬幣的值 int[] a ={1,3,5}; int[] dp =new int[12]; dp[0]=0; for(int i=1;i<=11;i++){ dp[i]=i; } for(int i=1;i<=11;i++){ for(int j=0;j<3;j++){ if(i>=a[j] && dp[i-a[j]]+1<dp[i]){ dp[i]=dp[i-a[j]]+1; } } } System.out.println("最少需要"+dp[11]+"個硬幣可以組成11"); // System.out.println(a[0]+" "+a[1]+" "+a[2]); for(int i=1;i<=11;i++){ System.out.print(dp[i]+" "); } } }
以上為特定11元
以下為推廣
package com.njit.dynamic_programming; public class Coin11ProblemCommonVersion { public static void main(String[] args) { //呼叫方法 在1 3 5 三個硬幣中找出最少的組合方式 組成 sum 變數為輸入的sum int inputCoin=11; int outputCoin= new Coin11ProblemCommonVersion().getMinCoin(inputCoin); System.out.println("當總數為 "+inputCoin+" 時,最少的硬幣數為:"+outputCoin); int[] outputCoinArray =new Coin11ProblemCommonVersion().getMinCoinArray(inputCoin); System.out.println("當總數為 "+inputCoin+" 時,各硬幣數為:"); for(int i=1;i<=inputCoin;i++){ System.out.println("dp["+i+"]="+outputCoinArray[i]); } } /** * 根據輸入,動態輸出硬幣數量 * * @param sum * @return * @see [類、類#方法、類#成員] */ public int getMinCoin(int sum){ int coin=0; int[] a ={1,3,5}; int[] dp = new int[sum+1]; dp[0]=0; for(int i=1;i<=sum;i++){ dp[i]=i; } for(int i=1;i<=sum;i++){ for(int j=0;j<3;j++){ if(i>=a[j] && dp[i-a[j]]+1<dp[i] ){ dp[i]=dp[i-a[j]]+1; } } } return dp[sum]; } /** * 輸入最後的硬幣數,返回過程中的所有最小硬幣數 * <功能詳細描述> * @param sum * @return * @see [類、類#方法、類#成員] */ public int[] getMinCoinArray(int sum){ int coin=0; int[] a ={1,3,5}; int[] dp = new int[sum+1]; dp[0]=0; for(int i=1;i<=sum;i++){ dp[i]=i; } for(int i=1;i<=sum;i++){ for(int j=0;j<3;j++){ if(i>=a[j] && dp[i-a[j]]+1<dp[i] ){ dp[i]=dp[i-a[j]]+1; } } } return dp; } }
2.MathTowerProblem (數塔問題:三角形結構,算出從下到上,數字總和最大的一條路徑的和)
狀態轉移方程
f[i][j] = max(f[i+1][j], f[i+1][j+1]) + map[i][j]
int[][] mathTower = new int[][]{{0,0,0,0,0,0},{0,7,0,0,0,0},{0,3,8,0,0,0}, {0,8,1,0,0,0},{0,2,7,4,4,0},{0,4,5,2,6,5}}; System.out.println("原始節點為:"); for(int i=1;i<=5;i++){ for(int j=1;j<=i;j++){ System.out.print(mathTower[i][j]+" "); } System.out.println(); } for(int i=5;i<=5;i--){ for(int j=1;j<i;j++){ mathTower[i-1][j]+=Math.max(mathTower[i][j], mathTower[i][j+1]); } } System.out.println("自底而上的最大數值路徑得到的值為: "+mathTower[1][1]); for(int k=1;k<=5;k++){ for(int t=1;t<=k;t++){ System.out.print(" "+mathTower[k][t]); } System.out.println(); }