1. 程式人生 > >動態規劃演算法(後附常見動態規劃例題及Java程式碼實現)

動態規劃演算法(後附常見動態規劃例題及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][m-peney[n]]

              不用第n種貨幣:dp[n-1][m],為什麼不使用第n種貨幣呢,因為penney[n]>m。

        這樣就可以求出當m>=penney[n]時 dp[n][m] = dp[n-1][m]+dp[n][m-peney[n]],否則,dp[n][m] = dp[n-1][m]

程式碼如下:

[java] view plain copy print?
  1. <span style=
    “font-size:18px;”>import java.util.;  
  2. publicclass Exchange {  
  3.     publicint countWays(int[] penny, int n, int aim) {  
  4.         // write code here
  5.         if(n==0||penny==null||aim<0){  
  6.          return0;     
  7.         }  
  8.         int[][] pd = newint[n][aim+1];  
  9.         for(int i=0;i<n;i++){  
  10.          pd[i][0] = 1;     
  11.         }  
  12.         for(int i=1;penny[0]*i<=aim;i++){  
  13.          pd[0][penny[0]*i] = 1;     
  14.         }  
  15.         for(int i=1;i<n;i++){  
  16.             for(int j=0;j<=aim;j++){  
  17.                 if(j>=penny[i]){  
  18.                     pd[i][j] = pd[i-1][j]+pd[i][j-penny[i]];  
  19.                 }else{  
  20.                     pd[i][j] = pd[i-1][j];  
  21.                 }  
  22.             }  
  23.         }  
  24.         return pd[n-1][aim];  
  25.     }  
  26. }</span>  
<span style=”font-size:18px;”>import java.util.;

public class Exchange {
public int countWays(int[] penny, int n, int aim) {
// write code here
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 plain copy print?
  1. <span style=“font-size:18px;”>import java.util.;  
  2. publicclass MinimumPath {  
  3.     publicint getMin(int[][] map, int n, int m) {  
  4.         // write code here
  5.        int[][] dp = newint[n][m];  
  6.         for(int i=0;i<n;i++){  
  7.             for(int j=0;j<=i;j++){  
  8.              dp[i][0]+=map[j][0];      
  9.             }  
  10.         }  
  11.         for(int i=0;i<m;i++){  
  12.             for(int j=0;j<=i;j++){  
  13.              dp[0][i]+=map[0][j];      
  14.             }  
  15.         }  
  16.         for(int i=1;i<n;i++){  
  17.             for(int j=1;j<m;j++){  
  18.              dp[i][j] = min(dp[i][j-1]+map[i][j],dp[i-1][j]+map[i][j]);     
  19.             }  
  20.         }  
  21.         return dp[n-1][m-1];  
  22.     }  
  23.     publicint min(int a,int b){  
  24.         if(a>b){  
  25.          return b;     
  26.         }else{  
  27.          return a;     
  28.         }  
  29.     }  
  30. }</span>  
<span style=”font-size:18px;”>import java.util.;

public class MinimumPath {
public int getMin(int[][] map, int n, int m) {
// write code here
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

解析:這是一個非常經典的為題,設f(n)為上n級臺階的方法,要上到n級臺階的最後一步有兩種方式:從n-1級臺階走一步;從n-1級臺階走兩步,於是就有了這個公式f(n) = f(n-1)+f(n-2);

程式碼如下:

[java] view plain copy print?
  1. <span style=“font-size:18px;”>import java.util.;  
  2. publicclass GoUpstairs {  
  3.     publicint countWays(int n) {  
  4.         // write code here
  5.         if(n<=2)  
  6.             return n;  
  7.         int f = 1%1000000007;  
  8.         int s = 2%1000000007;  
  9.         int t = 0;  
  10.         for(int i=3;i<=n;i++){  
  11.          t = (f+s)%1000000007;  
  12.          f = s;  
  13.          s = t;  
  14.         }  
  15.        return t;   
  16.     }  
  17. }</span>  
<span style=”font-size:18px;”>import java.util.;

public class GoUpstairs {
public int countWays(int n) {
// write code here
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 plain copy print?
  1. <span style=“font-size:18px;”>import java.util.*;  
  2. publicclass LCS {  
  3.     publicint findLCS(String A, int n, String B, int m) {  
  4.         // write code here
  5.         int[][] dp = newint[n][m];  
  6.         char[] a = A.toCharArray();  
  7.         char[] b = B.toCharArray();  
  8.        for(int i=0;i<n;i++){  
  9.            if(a[i]==b[0]){  
  10.                dp[i][0] = 1;  
  11.                for(int j=i+1;j<n;j++){  
  12.                    dp[j][0] = 1;  
  13.                }  
  14.                break;  
  15.            }  
  16.        }  
  17.          for(int i=0;i<m;i++){  
  18.            if(a[0]==b[i]){  
  19.                dp[0][i] = 1;  
  20.                for(int j=i+1;j<m;j++){  
  21.                    dp[0][j] = 1;  
  22.                }  
  23.                break;  
  24.            }  
  25.        }  
  26.        for(int i=1;i<n;i++){  
  27.            for(int j=1;j<m;j++){  
  28.                if(a[i]==b[j]){  
  29.                   dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);  
  30.                }else{  
  31.                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);  
  32.                }  
  33.            }  
  34.        }   
  35.         return dp[n-1][m-1];  
  36.     }  
  37.     publicint max(int a,int b,int c){  
  38.         int max = a;  
  39.         if(b>max)  
  40.             max=b;  
  41.         if(c>max)  
  42.             max = c;  
  43.         return max;  
  44.     }  
  45. }</span>  

相關推薦

動態規劃演算法常見動態規劃例題Java程式碼實現

原文連結 一、基本概念     動態規劃過程是:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱為動態規劃。 二、基本思想與策略     基本思想與分治法類似,也是

買什麼資料結構與演算法,這裡有:動態圖解十大經典排序演算法JAVA程式碼實現

上篇的動圖資料結構反響不錯,這次來個動圖排序演算法大全。資料結構與演算法,齊了。 幾張動態圖捋清Java常用資料結構及其設計原理 本文將採取動態圖+文字描述+正確的java程式碼實現來講解以下十大排序演算法: 氣泡排序 選擇排序 插入排序 希爾排序

常見14種經典排序演算法Java程式碼實現

尊重原創,轉載請標明出處   http://blog.csdn.net/abcdef314159 ,想了解更多演算法題可以關注微信公眾號“資料結構和演算法”,每天一題為你精彩解答。 一,氣泡排序 排序演算法其實有很多,氣泡排序基本上算是最簡單的一種

關於資料結構演算法中的比較排序(一)Java程式碼實現

     現在已經是10月份,秋招正在進行,不知道是不是有的人會和我一樣正在瘋狂的複習起資料結構,在這裡我將就常見的幾種比較排序做一些簡單的解析,同時附上具體的程式碼實現。 1.氣泡排序 氣泡排序通常是我們最先接觸道的比較排序的一種,具體排序步驟如下: 1.比較相鄰的元

十大排序演算法實現 十大經典排序演算法最強總結JAVA程式碼實現

十大經典排序演算法最強總結(含JAVA程式碼實現)   最近幾天在研究排序演算法,看了很多部落格,發現網上有的文章中對排序演算法解釋的並不是很透徹,而且有很多程式碼都是錯誤的,例如有的文章中在“桶排序”演算法中對每個桶進行排序直接使用了Collection.sort

基於矩陣分解的推薦演算法java程式碼實現

目前推薦系統中用的最多的就是矩陣分解方法,在Netflix Prize推薦系統大賽中取得突出效果。以使用者-專案評分矩陣為例,矩陣分解就是預測出評分矩陣中的缺失值,然後根據預測值以某種方式向用戶推薦。常見的矩陣分解方法有基本矩陣分解(basic MF),正則化矩

演算法】字串反轉的多種實現 java程式碼實現

原本還想再寫一個不使用額外記憶體的,發現貌似java實現不了, 如果哪位大神能實現歡迎補充 package com.billkang.algorithm; /** * 字串反轉 * * @au

十大經典排序演算法JAVA程式碼實現

排序演算法說明0.1 排序的定義對一序列物件根據某個關鍵字進行排序。0.2 術語說明穩定:如果a原本在b前面,而a=b,排序之後a仍然在b的前面;不穩定:如果a原本在b的前面,而a=b,排序之後a可能會出現在b的後面;內排序:所有排序操作都在記憶體中完成;外排序:由於資料太大

mahout推薦演算法——協同過濾推薦演算法java程式碼實現

什麼是協同過濾 協同過濾是利用集體智慧的一個典型方法。要理解什麼是協同過濾 (Collaborative Filtering, 簡稱 CF),首先想一個簡單的問題,如果你現在想看個電影,但你不知道具體看哪部,你會怎麼做?大部分的人會問問周圍的朋友,看看最近有什麼好看的電影推

十大經典排序演算法最強總結JAVA程式碼實現

0、排序演算法說明0.1 排序的定義對一序列物件根據某個關鍵字進行排序。0.2 術語說明穩定:如

最短路徑A*演算法原理java程式碼實現看不懂是我的失敗

package astar; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; imp

【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現

N皇后問題 問題描述 在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法,這稱為八皇后問題。 延伸一下,便為N皇后問題。 核心思想 解決N皇后問題有兩個關鍵點。一是如何進行放置棋子,二是如何驗證棋子是否符合

201809-1 CCFjava程式碼實現

問題描述   在一條街上有n個賣菜的商店,按1至n的順序排成一排,這些商店都賣一種蔬菜。   第一天,每個商店都自己定了一個價格。店主們希望自己的菜價和其他商店的一致,第二天,每一家商店都會根據他自己和相鄰商店的價格調整自己的價格。具體的,每家商店都會將第二天的菜價設定為自

歸併排序Java程式碼實現

歸併排序歸併排序採用的是分治(divide-and-conquer)法思想。(1)基本思想:將待排序元素分成大小大致相同的2個子集合,分別對2個子集合進行排序,最終將排好序的子集合合併成為所要求的排好序的集合。 (2)執行過程:(3)演算法思路:(4)Java程式碼實現如下:

樹的層次遍歷Java程式碼實現

  與樹的前中後序遍歷的DFS思想不同,層次遍歷用到的是BFS思想。一般DFS用遞迴去實現(也可以用棧實現),BFS需要用佇列去實現。 層次遍歷的步驟是: 1.對於不為空的結點,先把該結點加入到佇列中 2.從隊中拿出結點,如果該結點的左右結點不為空,就分別把左右結點加入到佇列

OpenCv學習筆記-數學形態學2灰度級膨脹和腐蝕c語言實現

一 基本概念 所謂的灰度級膨脹和腐蝕即將而知影象的二值形態學運算推廣到灰度影象上。對於一幅影象的腐蝕(膨脹)運算定義為對每個畫素賦值為某個領域內輸入影象灰度級的最小(或最大值)。在二值變換中的結構元素只代表一個領域,而在灰度級變化中,結構元素是一個二元函式,它規定了希

紅黑樹Red-Black tree初步詳解Java程式碼實現

紅黑樹Red-Blacktree初步詳解 本部落格的參考資料: 演算法導論 http://blog.csdn.net/v_july_v/article/details/6105630 http://www.cnblogs.com/skywang12345/p/3624343

替換檔案中某個字串並寫入新內容Java程式碼實現

import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWri

通過swagger2markup+asciidoctorj生成html和pdf文件並解決asciidoctorj生成的pdf檔案中文顯示不全問題maven方式java程式碼方式

通過swagger2markup+asciidoctorj生成html和pdf文件(maven方式及java程式碼方式) 任務:通過同事的json檔案生成相應的html和pdf文件 前言 開始時swagger2markup和asciidocto

單例模式java程式碼實現

應用單例模式時,類只能有一個物件例項,這麼做的目的是避免不一致狀態。 餓漢式單例:(立即載入) // 餓漢式單例 public class Singleton1 { // 指向自己例項的私有靜態引用,主動建立 private static Singlet