這里是簡單的動態規划問題。其實,如果我們學過數據結構,應該就接觸過動態規划問題,當時一直沒有反應過來。我們求最小生成樹用的是貪婪算法。而求最短路徑就是動態規划。從一個點出發,到另外每個點的最短距離。在求最短路徑問題中,取一點,然后與選取與這個點連接的,最小的一條邊,把這個點標上,然后求與標上點的連接的點的最短路徑。我們先來看這道題目吧
1.題目描述
將一個由N行數字組成的三角形,如圖所以,設計一個算法,計算出三角形的由頂至底的一條路徑,使該路徑經過的數字總和最小。

我們可以把這個橫過來看變成
7
3 4
8 5 0
2 7 4 4
4 5 2 6 5
從頂部到底部,只能從7走到3,或者8,然后從3走到8和1,8走到1和0 。。。。
我們自己計算最小路徑怎么算呢。假如從7出發,我們選擇與他們兩個的最長的一個,這是貪婪法,但是貪婪法有些時候不適用,比如這個圖,7的話,貪婪選最小的選3,但是最短路徑不是這條。
這道題目就要用到動態規划,我從底到頂部,依次求出從底部到上一層的最短路求出來。每次求最短路徑,再記錄下來就行。這道題目簡單的地方就是上層的點到下層的路只有兩條。
也就是說共有5層,用一個tem[][]來存放從底層到這個點的最短路徑,那么第5層從底到自己最短路徑還是本身,4,5,2,6,5。第四層的就是temp[4][j] = temp[4][j] + Min{temp[5][j],temp[5][j+1]},只有這兩條路與上一層直接相連,就能直接標上。同理遞歸調用。。。
2.輸入描述
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
3.輸出描述:
輸出每個點的從底部到這一點的最短路徑,都記錄下來。
17
10 14
14 7 6
6 9 6 9
4 5 2 6 5
4.代碼示例:
package a;
import java.util.Scanner;
public class DP {
static int qipan[][] = new int[5][5];
static int temp[][] = new int[5][5]; //用來存放的最短路徑的
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
for(int i=0;i<5;i++) {
for(int j=0;j<=i;j++) {
qipan[i][j] = scn.nextInt();
temp[i][j] = qipan[i][j];
}
}
dp(qipan,4);//把棋盤的第5層開始求。第5層最短路是本身,數組下標是4
//輸出棋盤
for(int i=0;i<5;i++) {
for(int j=0;j<=i;j++) {
System.out.printf("%-4d",temp[i][j]);
}
System.out.println();
}
//輸出路徑,這部分代碼只是用來輸出路徑的,調用print路徑
temp[0][0] = -1;
print(temp,0);
for(int i=0;i<5;i++) {
for(int j=0;j<=i;j++) {
if(temp[i][j] ==-1) {
System.out.printf("%-4d",qipan[i][j]);
}else {
System.out.printf("%-4d",0);
}
}
System.out.println();
}
}
private static void print(int[][] temp, int k) {
if( k==4 ) {
return;
}
for(int i=0;i<=k;i++) {
if(temp[k][i]==-1) {
if(temp[k+1][i]<temp[k+1][i+1]) {
temp[k+1][i] = -1;
}else {
temp[k+1][i+1] = -1;
}
}
}
print(temp, k+1);
}
private static void dp(int[][] qipan, int k) {
if(k ==0) {
return;
}
for(int j=0;j<k;j++) {
temp[k-1][j] = temp[k-1][j] + Math.min(temp[k][j], temp[k][j+1]);
}
dp(qipan, k-1);
}
}
