動態規划的概念對於新手來說枯燥難懂,就算看懂了,做題的時候依舊抓耳撓腮的毫無頭緒,這些比較難理解的算法,還是需要根據例子來一步步學習和理解,從而熟練掌握,下面,咱們就通過一個簡單的小例子來學習動態規划:
數字三角形(POJ1163)
在上面的數字三角形中尋找一條從頂部到底邊的路徑,使得路徑上所經過的數字之和最大。
路徑上的每一步都只能往左下或 右下走。只需要求出這個最大和即可,不必給出具體路徑。 三角形的行數大於1小於等於100,數字為 0 - 99
輸入格式:
5 //表示三角形的行數 接下來輸入三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
要求輸出最大和
咱們來分析這道題:
1.需要有一個變量 n 來存儲輸入的行數
2.需要一個二維數組 a 來存儲輸入的數字三角形
3.需要另一個同樣大小的二維數組 b,用來存儲到每一層的每一個數的最短路徑,
例如:
到三角形的第三層,有兩條路會經過1,
由於7+3=10<7+8=15,所以b數組的1的位置存儲的是最短路徑7—>3—>1等於11,
而在最兩邊的,就直接累加就ok了,7+3+8=18,7+8+0=15
這也是這個程序的核心部分,代碼如下:
因為第一層跟a數組的第一層相同,所以i從1開始循環
然后遍歷最后一層,求出最小值就ok啦
b數組最后的值
完整代碼如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sca = new Scanner(System.in); int n = sca.nextInt(); int[][] a = new int[n][n]; int[][] b = new int[n][n]; int min; for(int i = 0;i<n;i++){ for(int j = 0;j<=i;j++){ a[i][j] = sca.nextInt(); } } b[0][0] = a[0][0]; for(int i = 1;i<n;i++){ for(int j = 0;j<=i;j++){ if(j==0)//左側,直接相加 b[i][j] = b[i-1][j]+a[i][j]; else if(j==i)//右側,直接相加 b[i][j] = b[i-1][j-1]+a[i][j]; else//中間,需要用min函數求經過這條路的最短路徑 b[i][j] = Math.min(b[i-1][j-1],b[i-1][j])+a[i][j]; } } min = b[n-1][0]; for(int i = 1;i<b[n-1].length;i++){ if(b[n-1][i]<min) min = b[n-1][i]; } System.out.println(min); } }
總結一下動態規划的解題思路:
1,將原問題分解為簡單的子問題,子問題求出來之后,原問題也就很容易得到了
2,確定狀態轉移方程
這道題的狀態轉移方程: