1. 程式人生 > >動態規劃演算法小結(二)石子問題

動態規劃演算法小結(二)石子問題

我們來看個動態規劃的例子吧:

問題描述  在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。輸入格式  輸入第一行包含一個整數n,表示石子的堆數。
  接下來一行,包含n個整數,按順序給出每堆石子的大小 。輸出格式  輸出一個整數,表示合併的最小花費。樣例輸入5
1 2 3 4 5樣例輸出33

程式碼:

  1. import java.util.Scanner;  
  2. publicclass Main {  
  3.     publicstaticvoid main(String[] args) {  
  4.         Scanner in = new
     Scanner(System.in);  
  5.         int n = in.nextInt();  
  6.         int[] a = newint[1010];  
  7.         int[][] temp = newint[1010][1010];  
  8.         int[][] dp = newint[1010][1010];  
  9.         for (int i=1; i<=n; i++) {  
  10.             a[i] = in.nextInt();  
  11.             temp[i][i] = a[i];  
  12.         }  
  13.         for (int i=1; i<n; i++) {  
  14.             for(int j=i+1; j<=n; j++) {  
  15.                 temp[i][j] = temp[i][j-1] + a[j];  
  16.             }  
  17.         }  
  18.         for (int r=2; r<=n; r++) {  
  19.             for (int i=1; i<=n-r+1; i++) {  
  20.                 int j=i+r-1;  
  21.                 dp[i][j] = Integer.MAX_VALUE;  
  22.                 for
     (int k=i; k<j; k++) {  
  23.                     if(dp[i][j] > dp[i][k] + dp[k+1][j])  
  24.                         dp[i][j] = dp[i][k] + dp[k+1][j];  
  25.                 }  
  26.                 dp[i][j] += temp[i][j];  
  27.             }  
  28.         }  
  29.         System.out.println(dp[1][n]);  
  30.     }  

演算法書上把解動態規劃問題分為四步:

(1)找出最優解性質

(2)遞迴定義最優解

(3)以自底向上的方式算出最優解

(4)根據計算最優值時得到的資訊構造最優解

第一步是確定該問題是否有最優子結構,石子問題中我們可以這樣分析,最後一步是將最後的兩堆石子a和b合併起來成為c,那我們就可以想到c的花費最小時,a、b是否也是取最小呢?顯然,如果不是那意味著c也可以取更小的值。所以石子問題的最優解包含其子問題的最優解。

第二步是建立遞迴關係。為了方便我們可以使用dp[i][j]表示第i堆石子到第j堆石子的最優值,我們要建立dp[i][j]與其子問題的遞迴關係:

             顯然i=j時,石子沒有合併,就沒有花費,dp[i][j]=0;

             i<j時,我們用k(k>=i&&k<=j)把dp[i][j]分成dp[i][k]與dp[k+1][j]兩個部分,那麼dp[i][j]=dp[i][k]+dp[k+1][j]+temp[i][j]//需要另一個數組temp[i][j]儲存第i堆石子到第j堆石子的石子總數

第三步根據第二步的遞迴思路計算dp[1][n],底層i/j從1/2遍歷到n-1/n,儲存到dp後,再往上1/3遍歷到n-2/n...一直到最後1/n,每一個i/j都需要用k(k>=i&&k<=j)分成兩部分,通過比較k取不同值時的dp[i][j]得到最小花費。

第四步構造最優解,這個問題的最優解就是最後a[1][n]的值啦。對第四步有疑問0-1揹包問題會有說明。