1. 程式人生 > >BFS最短路徑問題新手快速入門

BFS最短路徑問題新手快速入門

我們遇到的迷宮問題中,有很大一部分可以用BFS來解。解決這類問題可以很大地提升你的能力與技巧,我會試著幫助你理解如何使用BFS來解題。這篇文章是基於一個簡單例項展開來講的

例題:
第一行兩個整數n, m,為迷宮的長寬。
接下來n行,每行m個數為0或1中的一個。0表示這個格子可以通過,1表示不可以。假設你現在已經在迷宮座標(1,1)的地方,即左上角,迷宮的出口在(n,m)。每次移動時只能向上下左右4個方向移動到另外一個可以通過的格子裡,每次移動算一步。資料保證(1,1),(n,m)可以通過。
輸出格式
  第一行一個數為需要的最少步數K。
  第二行K個字元,每個字元∈{U,D,L,R},分別表示上下左右。如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個。
 樣例輸入
Input Sample 1:
3 3
0 0 1
1 0 0
1 1 0

Input Sample 2:
3 3
0 0 0
0 0 0
0 0 0
樣例輸出
Output Sample 1:
4
RDRD

Output Sample 2:
4
DDRR

BFS,屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的所有節點,以找尋結果。換句話說,它並不考慮結果的可能位置,徹底地搜尋整張圖,直到找到結果為止。
虛擬碼

queue.add(起點);
while(佇列不為空){
    取出隊首點
    if(如果為終點)
        結束
    //不為終點,繼續向下走
    for(方向)
        ...
}

下面貼上例題的程式碼

public
class test3 { static int[][] one = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };//上下左右移動座標的變化 static String[] nextpath = { "U", "D", "L", "R" };//上下左右移動的表示 static class point {//點類記錄當前座標,步數,路徑 int x, y, step;//step表示從出發到當前點經過幾步 String path;//path表示從出發到當前點經過路徑 public point(int
x, int y, int step, String path) { this.x = x; this.y = y; this.step = step; this.path = path; } } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); int[][] a = new int[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { a[i][j] = in.nextInt(); } } bfs(a, n, m); } //按字典序較小選擇路徑 public static boolean judge(String A, String B) { char[] arrayA = A.toCharArray(); char[] arrayB = B.toCharArray(); for (int i = 0, len = A.length(); i < len; i++) { if (arrayA[i] < arrayB[i]) return false; } return true; } //判斷點是否出界或被訪問過 public static boolean check(int[][] matrix, point a) { int n = matrix.length - 1, m = matrix[0].length - 1; if (a.x < 0 || a.x > n || a.y < 0 || a.y > m || matrix[a.x][a.y] == 1) return false; return true; } //搜尋 static void bfs(int[][] a, int n, int m) { ArrayList<point> list = new ArrayList<point>(); list.add(new point(0, 0, 0, ""));//向佇列中加入第一個點 int minStep = Integer.MAX_VALUE;//最小步數 String minPath = "";//最短路徑 while (list.size() != 0) { point b = list.get(0);//當佇列中有點時,取出點比較是否為終點 list.remove(0);//刪除該點 if (b.x == n - 1 && b.y == m - 1) { if (minStep > b.step) { minStep = b.step; minPath = b.path; } else if (minStep == b.step) { if (judge(minPath, b.path)) { minPath = b.path; } } continue; } //如果不是終點,依次嘗試訪問上下左右,並加入佇列繼續迴圈 for (int i = 0; i < 4; i++) { int x = b.x + one[i][0]; int y = b.y + one[i][1]; int step = b.step + 1; String path = b.path + nextpath[i]; point p = new point(x, y, step, path); if (check(a, p)) { list.add(p); a[x][y] = 1; } } } System.out.println(minPath + "\n" + minStep);//迴圈結束輸出最短步數及路徑 return; } }

執行結果

3 3
0 1 0
0 1 0
0 0 0
DDRR
4

如果無通路則會輸出Integer.Max_Value