這篇文章寫給自己以后復習和個個入門朋友:提示同學們一定耐心看完解釋 哪怕看得很難受,我是新手我懂大家的心煩。看完后慢慢體會代碼
我們假設迷宮為如下狀況:
{0,0,1,0}
{0,0,1,0}
{0,0,0,0}
{0,0,1,0},
1為牆無法通行 只可以上下左右四個方向走動;目的:從左上角到右下角
DFS深度優先搜索算法思想:這里百度百科有很多 我這里推薦一個http://rapheal.iteye.com/blog/1526863;稍微看一下就好。由於是別人所以尊重原創所以我就不復制了。
那么用DFS解迷宮所有路徑:我們在這里采用遞歸。我們從左上角當成“當前點”開始把出發坐標壓入一個棧。每當入棧一個坐標 就把 迷宮所在所標的數值改為-1(當然1也可以,個人這樣覺得比較好因為還可以復原迷宮);從左上角開始后從 左上角四個方向(上右下左)開始判斷能否走通。比如我們判斷當前點上方點的值是否為0;如果是0才可行走。如果上方可以走那么把此點當成當前點。繼續判斷“當前點”的四個方向,注意上一個當前點不賦值為-1 你就發現那么又要走回去了,因為上一個“當前點”是他左右上下其中的一個嘛。發生死遞歸等 比如java提示" java.lang.StackOverflowError。可能剛學的不知道什么意思,那么我們就先記住 “防止重復遍歷此點”。
那么配圖解釋:
以上代表一個迷宮,每一格代表每一個通道。
綠色:牆
白色:可以走的路徑;
藍色:上一個當前點(本質是白色方便新手理解);
紅色:當前點;(本質是白色)
解釋:假如走到紅色的地方 此時我們又要判斷紅色的左右上下可以走否。我們發現紅色右是綠色 (牆相當於迷宮的1嘛)。左手邊是白色(因為表示上一個當前點所以變成藍色)所以你將走回去。你走過來走回去干嘛?下面不是還有路嗎?所以你要記得把所有走過的節點設置為綠色(設置為1);
最后我們一個個遍歷當遇到一個點無法通過時或者找到終點的話返回上一個遞歸(如果是找到結果,記得先輸出逆序棧的坐標,就是其中一個迷宮出路) 返回后記得出棧、並把當前節點設置回0;原因“走不通返回上一個路口嘛。至於為什么重新設置回0的原因比較難闡述 :‘另一個路徑又經過這里去尋找終點,卻發現這條被走過就放棄從這里出發(其實沒走過,是上一個路徑走的),在這里有些人有人再想 【你說的和上面那么死遞歸不是沖突嗎?】 其實這里沒有沖突:假設我們當前點位B我們上一個當前點為''C(位於C的上方)’、 那么當前點為B ,假設B點除了C方向都是不能通行,而C又是被走過的節點。所以原路返回到到C(出棧一次) 並且B賦值為0; 回到C后我們繼續檢測其他方向(除了C方向也就是上),這樣就不會再去判斷上方,因為上下左右只會走一次走過上方發現走不通 就不會在去上了,所以B的值是0又怎么樣? ”
代碼:
import java.awt.Point; import java.util.Stack; public class Main { //迷宮我們用二維數組表示, //至於為什么邊緣都是1,是我加上去的 這樣你就可以防止邊界越界。 //慢慢看后面的代碼就知道了 public static int maze[][]={ //0 1 2 3 4 5 {1,1,1,1,1,1},//0 {1,0,0,1,0,1},//1 {1,0,0,1,0,1},//2 {1,0,0,0,0,1},//3 {1,0,0,1,0,1},//4 {1,1,1,1,1,1},//5 }; //四個方向嘛 上右下左(時針順序)比如第一個item第一個坐標(-1,0) //我們要計算當前點上面坐標 就加上 item第一個坐標值 //假設我們計算(X,Y) 上方坐標 那么就是(X+(-1),Y+0)左右下同理 static Point item [] ={new Point(-1,0),new Point(0,1),new Point(1,0),new Point(0,-1)}; //迷宮實際 行數和列數 static int row=4; static int colum=4; //用來保存坐標的棧 static public Stack<Point> stack =new Stack<Point>(); public static void main(String[] args) { // TODO Auto-generated method stub DFS(row,colum,new Point(1,1)); } //參數信息row colum實際的迷宮總行數和列數 這兩個固定的 //參數信息point當前節點 public static void DFS(int row,int colum,Point point){ //我們到左下角為終點 起點為左上角 maze[point.x][point.y]=-1;//走過當前節點所以賦值為-1 stack.add(point); // System.out.println("入棧"+point); int x,y; x= point.x; y= point.y; //如果是最后結果 if(row==point.x && colum==point.y){ printPath(); //給最后一個節點賦值回0 不然別的路徑怎么走得到? maze[point.x][point.y]=0; }else{ //4個方向分別測試,比如從當前節點向上走不到終點那么返回 //那么在向右走 for (int i = 0; i < item.length; i++) { Point temp =new Point(x+item[i].x,y+item[i].y); if(maze[x+item[i].x][y+item[i].y]==0){ //如果當前方向可以走,那么進去下一個方向 DFS(Main.row,Main.colum,temp); } } } stack.pop();//出棧 maze[point.x][point.y]=0; // System.out.println("出棧"+point); } //逆序輸出棧里面的東西 public static void printPath(){ System.out.println("-----------------------"); for (Point point : Main.stack) { System.out.print("["+point.x+","+point.y+"]"); } System.out.println("-----------------------"); } }
最后再附上一個非遞歸版: