生活随笔
收集整理的這篇文章主要介紹了
动态规划算法入门---java版
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載:http://blog.csdn.net/p10010/article/details/50196211
?
動態規劃算法(后附常見動態規劃為題及Java代碼實現)
一、基本概念
?? ?動態規劃過程是:每次決策依賴于當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱為動態規劃。
二、基本思想與策略
?? ?基本思想與分治法類似,也是將待求解的問題分解為若干個子問題(階段),按順序求解子階段,前一子問題的解,為后一子問題的求解提供了有用的信息。在求解任一子問題時,列出各種可能的局部解,通過決策保留那些有可能達到最優的局部解,丟棄其他局部解。依次解決各子問題,最后一個子問題就是初始問題的解。
?? ?由于動態規劃解決的問題多數有重疊子問題這個特點,為減少重復計算,對每一個子問題只解一次,將其不同階段的不同狀態保存在一個二維數組中。
?? ?與分治法最大的差別是:適合于用動態規劃法求解的問題,經分解后得到的子問題往往不是互相獨立的(即下一個子階段的求解是建立在上一個子階段的解的基礎上,進行進一步的求解)。
以上都過于理論,還是看看常見的動態規劃問題吧!!!
三、常見動態規劃問題
?? 1、找零錢問題
?? 有數組penny,penny中所有的值都為正數且不重復。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim(小于等于1000)代表要找的錢數,求換錢有多少種方法。
給定數組penny及它的大小(小于等于50),同時給定一個整數aim,請返回有多少種方法可以湊成aim。
測試樣例:
[1,2,4],3,3
返回:2
解析:設dp[n][m]為使用前n中貨幣湊成的m的種數,那么就會有兩種情況:
???????????? 使用第n種貨幣:dp[n-1][m]+dp[n-1][m-peney[n]]
????????????? 不用第n種貨幣:dp[n-1][m],為什么不使用第n種貨幣呢,因為penney[n]>m。
??????? 這樣就可以求出當m>=penney[n]時 dp[n][m] = dp[n-1][m]+dp[n-1][m-peney[n]],否則,dp[n][m] = dp[n-1][m]
代碼如下:
[java]?view plaincopy
<span?style="font-size:18px;">import?java.util.*;?? ?? public?class?Exchange?{?? ????public?int?countWays(int[]?penny,?int?n,?int?aim)?{?? ?????????? ????????if(n==0||penny==null||aim<0){?? ?????????return?0;????? ????????}?? ????????int[][]?pd?=?new?int[n][aim+1];?? ????????for(int?i=0;i<n;i++){?? ?????????pd[i][0]?=?1;????? ????????}?? ????????for(int?i=1;penny[0]*i<=aim;i++){?? ?????????pd[0][penny[0]*i]?=?1;????? ????????}?? ????????for(int?i=1;i<n;i++){?? ????????????for(int?j=0;j<=aim;j++){?? ????????????????if(j>=penny[i]){?? ????????????????????pd[i][j]?=?pd[i-1][j]+pd[i][j-penny[i]];?? ????????????????}else{?? ????????????????????pd[i][j]?=?pd[i-1][j];?? ????????????????}?? ????????????}?? ????????}?? ????????return?pd[n-1][aim];?? ????}?? }</span>??
2、走方格問題
? 有一個矩陣map,它每個格子有一個權值。從左上角的格子開始每次只能向右或者向下走,最后到達右下角的位置,路徑上所有的數字累加起來就是路徑和,返回所有的路徑中最小的路徑和。
給定一個矩陣map及它的行數n和列數m,請返回最小路徑和。保證行列數均小于等于100.
測試樣例:
[[1,2,3],[1,1,1]],2,3
返回:4
解析:設dp[n][m]為走到n*m位置的路徑長度,那么顯而易見dp[n][m] = min(dp[n-1][m],dp[n][m-1]);
?
代碼如下:
[java]?view plaincopy
<span?style="font-size:18px;">import?java.util.*;?? ?? public?class?MinimumPath?{?? ????public?int?getMin(int[][]?map,?int?n,?int?m)?{?? ?????????? ???????int[][]?dp?=?new?int[n][m];?? ????????for(int?i=0;i<n;i++){?? ????????????for(int?j=0;j<=i;j++){?? ?????????????dp[i][0]+=map[j][0];?????? ????????????}?? ????????}?? ????????for(int?i=0;i<m;i++){?? ????????????for(int?j=0;j<=i;j++){?? ?????????????dp[0][i]+=map[0][j];?????? ????????????}?? ????????}?? ????????for(int?i=1;i<n;i++){?? ????????????for(int?j=1;j<m;j++){?? ?????????????dp[i][j]?=?min(dp[i][j-1]+map[i][j],dp[i-1][j]+map[i][j]);????? ????????????}?? ????????}?? ????????return?dp[n-1][m-1];?? ????}?? ????public?int?min(int?a,int?b){?? ????????if(a>b){?? ?????????return?b;????? ????????}else{?? ?????????return?a;????? ????????}?? ????}?? }</span>??
3、走臺階問題
有n級臺階,一個人每次上一級或者兩級,問有多少種走完n級臺階的方法。為了防止溢出,請將結果Mod 1000000007
給定一個正整數int n,請返回一個數,代表上樓的方式數。保證n小于等于100000。
測試樣例:
1
返回:1
解析:
這個問題典型的斐波那契數列問題。
假設N級樓梯的爬法有A(N)種方法,假設第一步上一個臺階,則上法有A(N-1)種,如果第一步上兩個臺階,則上法有A(N-2)種方法,因此:
A(N)=A(N-1)+A(N-2)
而A(1)=1,A(2)=2,則A(3)=A(1)+A(2)=3,A(4)=A(2)+A(3)=5,……
從而可以遞推出N階臺階時的方法。
這是一個非常經典的為題,設f(n)為上n級臺階的方法,要上到n級臺階的最后一步有兩種方式:從n-1級臺階走一步;從n-1級臺階走兩步,于是就有了這個公式f(n) = f(n-1)+f(n-2);
代碼如下:
[java]?view plaincopy
<span?style="font-size:18px;">import?java.util.*;?? ?? public?class?GoUpstairs?{?? ????public?int?countWays(int?n)?{?? ?????????? ????????if(n<=2)?? ????????????return?n;?? ????????int?f?=?1%1000000007;?? ????????int?s?=?2%1000000007;?? ????????int?t?=?0;?? ????????for(int?i=3;i<=n;i++){?? ?????????t?=?(f+s)%1000000007;?? ?????????f?=?s;?? ?????????s?=?t;?? ????????}?? ???????return?t;??? ????}?? }</span>??
4、最長公共序列數
給定兩個字符串A和B,返回兩個字符串的最長公共子序列的長度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最長公共子序列。
給定兩個字符串A和B,同時給定兩個串的長度n和m,請返回最長公共子序列的長度。保證兩串長度均小于等于300。
測試樣例:
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6
解析:設dp[n][m] ,為A的前n個字符與B的前m個字符的公共序列長度,則當A[n]==B[m]的時候,dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]),否則,dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
代碼如下:
[java]?view plaincopy
<span?style="font-size:18px;">import?java.util.*;?? ?? public?class?LCS?{?? ????public?int?findLCS(String?A,?int?n,?String?B,?int?m)?{?? ?????????? ????????int[][]?dp?=?new?int[n][m];?? ????????char[]?a?=?A.toCharArray();?? ????????char[]?b?=?B.toCharArray();?? ???????for(int?i=0;i<n;i++){?? ???????????if(a[i]==b[0]){?? ???????????????dp[i][0]?=?1;?? ???????????????for(int?j=i+1;j<n;j++){?? ???????????????????dp[j][0]?=?1;?? ???????????????}?? ???????????????break;?? ???????????}?? ????????????? ???????}?? ?????????for(int?i=0;i<m;i++){?? ???????????if(a[0]==b[i]){?? ???????????????dp[0][i]?=?1;?? ???????????????for(int?j=i+1;j<m;j++){?? ???????????????????dp[0][j]?=?1;?? ???????????????}?? ???????????????break;?? ???????????}?? ????????????? ???????}?? ???????for(int?i=1;i<n;i++){?? ???????????for(int?j=1;j<m;j++){?? ???????????????if(a[i]==b[j]){?? ??????????????????dp[i][j]?=?max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);?? ???????????????}else{?? ???????????????????dp[i][j]?=?Math.max(dp[i-1][j],dp[i][j-1]);?? ???????????????}?? ????????????????????? ???????????}?? ???????}??? ?????????? ????????return?dp[n-1][m-1];?? ????}?? ????public?int?max(int?a,int?b,int?c){?? ????????int?max?=?a;?? ????????if(b>max)?? ????????????max=b;?? ????????if(c>max)?? ????????????max?=?c;?? ????????return?max;?? ????}?? }</span> ?
總結
以上是生活随笔為你收集整理的动态规划算法入门---java版的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。