走迷宮問題是深度優先搜索的一個典型應用,通常迷宮的形狀如下
0爲可走的道路,1爲牆壁。通常情況下一些變種的模型,會加入一些特殊項,有別的意思,比如數字5代表鑰匙,當然複雜模型先不討論,從最簡單的開始。
深度優先搜索的思想其實就是枚舉式的遞歸,不斷的對當前狀態下進行對下一狀態轉移的進行枚舉,直到找到解。在迷宮問題中,任意一個可以走的點都有4種轉移狀態(往上,往下,往左,往右),當然不是每一種狀態的轉移都是合法的,比如,以左上角(假設)點爲起點,起點狀態無法轉移到:上,左,右這三種狀態。只有往下是可以進行轉移的,當我們往下轉移時,轉移時合法的,就遞歸進一層,此時,我們在新的狀態下,重複進行枚舉可轉移狀態並進一步遞歸進去,然後對合法的狀態進行遞歸來搜索解,當搜索到某一狀態搜索完所有可轉移的狀態時依然無法找到解,就進行回溯到上一層狀態,遞歸轉移到下一狀態。
深度優先搜索可以用樹的前序遍歷來理解,我們一直往深處走,走到頭了就往回走,然後選則另外一條路繼續往深處走,直到全部走完或這找到我們要的條件
下面結合代碼來理解
#include<iostream>
#include<math.h>
#include<memory.h>
#include<stack>
using namespace std;
//這是設定的狀態轉移變量,分爲上下左右4組,每一組的值分別代表X,Y的偏移
int dst[4][2]={//上下左右
-1,0,
1,0,
0,-1,
0,1
};
//迷宮,終點設置爲數字3,已經走過的節點設置爲4
int maze[5][5] = {
0,1, 0, 0, 0,
0,1, 0, 1, 0,
0,0, 0, 0, 0,
0,1, 1, 1, 0,
0,0, 0, 1, 3,
};
void dfs(int x,int y)
{
if(maze[x][y]==3)//判斷是否走到了終點,走到了就是輸出找到的解
{//if裏面是對可行解的一個判斷表達式,裏面的話就執行我們得到一個解後要進行的操作。
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
cout<<maze[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
return ;
}
for(int i=0;i<4;i++)//枚舉轉移狀態
{
int nextx = x+dst[i][0];//計算轉移狀態
int nexty = y+dst[i][1];
//下面這裏就是DFS的核心部分了,判斷轉移是否合法,合法的遞歸進去,不合法的,不進行搜索,if需要包含全部判斷條件,不可缺一,否則搜索回出問題
if(nextx>=0 && nextx<=4 && nexty>=0 && nexty<=4&&(maze[nextx][nexty]!=1)&&(maze[nextx][nexty]!=4))//判斷下一個要走的點是否合法,在迷宮的題目裏面主要是判斷轉移的點能不能走
{
maze[x][y] = 4;//設置當前點爲走過
dfs(nextx,nexty);//進一步搜索
maze[x][y] = 0;//退出來設置爲沒有走過,這樣在回溯進行後續搜索時,不會影響對路徑的搜索
}
}
return ;
}
int main()
{
dfs(0,0);//初始調用
return 0;
}
輸出結果