1. 程式人生 > >求迷宮最短路徑【佇列+回溯】

求迷宮最短路徑【佇列+回溯】

       求迷宮的最短路徑(0表示通路,1表示受阻)

問題:有一個迷宮,求從入口到出口的最短路徑,其中0表示通路,1表示受阻,規定向下是X軸,向右是Y軸

輸入:第一個數迷宮x軸的長度,第二個數迷宮y軸的長度,緊接著入口點的座標和出口的座標,之後是一個迷宮

輸出:迷宮所走的路徑的座標

樣例:

INPUT:

6 8
1 1
6 8

0 1 1 1 0 1 1 1
1 0 1 0 1 0 1 0
0 1 0 0 1 1 1 1
0 1 1 1 0 0 1 1
1 0 0 1 1 0 0 0
0 1 1 0 0 1 1 0

OUT:

(1,1)-->(2,2)-->(3,3)-->(3,4)-->(4,5)-->(4,6)-->(5,7)-->(6,8)

    

基本思想:從迷宮入口(1,1)出發,向四周搜尋,記下所有一次能通達的座標p11,p12,…p1k,然後從p11,p12,…p1k出發,向四周搜尋,標記搜尋過的點……直至達到出口點(mn),然後從出口點沿搜尋路徑回溯直至入口。

 

注意點:

1.為什麼從(1,1)點出發而不從(0,0)點出發?

若從(0,0)點出發向四周八個點進行搜尋是搜尋不了的,其實就是為了程式碼的統一

2.為什麼使用佇列這種資料結構?為什麼使用佇列記錄的路徑是最短的呢?

1.仔細分析一下這個迷宮,我們從(1,1)點出發,到下一個點(2,2),在(2,2)這裡有兩種情況都應該記錄下來,以此類推把之後的搜尋到的記錄都記錄到最後,先搜尋到的應該先進行繼續搜尋,這種邏輯結構符合佇列的邏輯結構

2.對角線最短這應該大家都懂,假設有一個迷宮是這樣的

序號為1的地方表示入口而序號為9的地方表示出口,顯而易見這個迷宮其實全是通路的,從起點都能到達終點

從序號1向四周搜尋,搜到的應該是序號2,4,5把這三個點儲存到佇列中,從序號2開始搜尋到序號3儲存到佇列中,序號4也是一樣,把7,8兩個點加入到佇列中,但是從5開始搜尋的時候儲存的是6,9兩個點,最先找到終點的一定是5.因為2或者4還要很多步數一定是比序號5慢的

下面是程式碼:

package 佇列的應用_搜迷宮最短路徑;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class FindMinLoad {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int x = in.nextInt();//X軸長度
		int y = in.nextInt();//Y軸
		int[][] mg = new int[x+2][y+2];//迷宮
		int Xrk = in.nextInt();//入口
		int Yrk = in.nextInt();
		int Xck = in.nextInt();//出口
		int Yck = in.nextInt();
		for (int i = 0; i < mg[0].length; i++) {
			mg[0][i] = 1;
			mg[x+1][i] = 1;
		}
		for (int i = 0; i < mg.length; i++) {
			mg[i][0] = 1;
			mg[i][y+1] = 1;
		}
		for (int i = 1; i < mg.length-1; i++) {
			for (int j = 1; j < mg[i].length-1; j++) {
				mg[i][j] = in.nextInt();
			}
		}	
//		for (int i = 0; i < mg.length; i++) {
//			for (int j = 0; j < mg[i].length; j++) {
//				System.out.print(mg[i][j]+" ");
//			}
//			System.out.println();
//		}
		//if(x==1 && y==1) {
			//System.out.println("0");
		//}else {
			int[][] queue = new int[x*y][3];
			queue[0][0] = Xrk;
			queue[0][1] = Yrk;
			queue[0][2] = -1;
			int front = 0;
			int rear = 1;
			OUT:
			while(front!=rear) {
				mg[queue[front][0]][queue[front][1]] = 1;
				for (int i = queue[front][0]-1; i <= queue[front][0]+1; i++) {
					for (int j = queue[front][1]-1; j <= queue[front][1]+1; j++) {
						if(mg[i][j]==0) {//通路記錄下
							queue[rear][0] = i;
							queue[rear][1] = j;
							queue[rear++][2] = front;
							mg[i][j]=1;
							if(i==Xck && j==Yck) {
								break OUT;
							}
						}
					}
				}
				//System.out.println((queue[rear-1][0]!=Yck)+" "+(queue[rear-1][1]!=Xck));
				front++;
			}
			List<String> list = new ArrayList<String>();
			for (int i = rear-1; i>=0; i--) {
				//System.out.println("("+queue[i][0]+","+queue[i][1]+")");
				list.add("("+queue[i][0]+","+queue[i][1]+")");
				i = queue[i][2]+1;
			}
			for (int i = list.size()-1; i>0; i--) {
				System.out.print(list.get(i)+"-->");
			}
			System.out.print(list.get(0));
			
		//}
		
	}
}