動態規划入門——數字三角形(Java)


動態規划的概念對於新手來說枯燥難懂,就算看懂了,做題的時候依舊抓耳撓腮的毫無頭緒,這些比較難理解的算法,還是需要根據例子來一步步學習和理解,從而熟練掌握,下面,咱們就通過一個簡單的小例子來學習動態規划:

數字三角形(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,確定狀態轉移方程

這道題的狀態轉移方程:

 

 

 

 

 

動態規划一般可分為線性動規,區域動規,樹形動規,背包動規四類。
舉例:
線性動規:攔截導彈,合唱隊形,挖地雷,建學校,劍客決斗等;
區域動規:石子合並, 加分二叉樹,統計單詞個數,炮兵布陣等;
樹形動規:貪吃的九頭龍,二分查找樹,聚會的歡樂,數字三角形等;
背包問題:01背包問題,完全背包問題,分組背包問題,二維背包,裝箱問題,擠牛奶(同濟ACM第1132題)等;
應用實例:
最短路徑問題 ,項目管理,網絡流優化等;
以上例子,每類挑選一題或兩題練習即可
 
 
 
所有的算法都需要多加練習,應用起來才能得心應手,希望我的這篇博客能給各位愛學習的同伴們帶去一些收獲,我也是新手,大家共同努力,加油!

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM