二維整數矩陣a[N][N]表示一個迷宮,矩陣左上角表示迷宮入口,右下角表示出口。矩陣的元素爲0表示可以通過,爲1表示不能夠通過。如
maze[5][5]=
{0, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 1, 0, 1, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0};
則迷宮的一條通往出口的路徑爲(0, 0)->(1, 0)->(2, 0)->(3, 0)->(4, 0)->(4, 1)->(4, 2)->(4, 3)->(4, 4)。
設計一個算法,求通往迷宮出口的所有路徑。
可以考慮使用DFS算法,將已經訪問過的矩陣元素做一個標記,以防止路徑產生迴路,從而產生死循環。但是,簡單的對元素進行訪問標記會遺漏一些路徑。
這是因爲,通往迷宮出口的不同路徑有可能有交點。當所有路徑的交點多於兩個時,由於先獲取的路徑會將交點元素標記爲已經訪問。當存在其他通過該節點的路徑
時,由於該交點已經被標記爲已訪問,所以其他的通過該交點的路徑將被忽略。
解決這個問題只需要對算法稍加改動即可。思路爲:當某一個節點DFS完成後,擦除該節點的訪問痕跡。
代碼如下:
#include<iostream>
#include<deque>
using namespace std;
class Point
{
public:
int i;
int j;
Point(int x, int y)
{
i=x;
j=y;
}
};// 節點座標結構體
deque<Point> q;// 用一個隊列記錄路徑
int N=5;// 迷宮的大小
int maze[5][5]=
{0, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 1, 0, 1, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0};// 迷宮矩陣
int path[5][5]=
{0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0};// 訪問標記矩陣
void dfs(int i, int j);
void main()
{
path[0][0]=1;
q.push_back(Point(0, 0));
dfs(0, 0);
q.pop_back();
//system("pause");
}
void dfs(int i, int j)
{
if(N-1==i && N-1==j)
{
path[i][j]=0;
cout<<"Path:"<<endl;
for(deque<Point>::iterator it=q.begin(); it!=q.end(); it++)
{
cout<<(*it).i<<", "<<(*it).j<<endl;
}
return;
}
if(i>0 && 1!=maze[i-1][j] && 1!=path[i-1][j])
{
path[i-1][j]=1;// 標記節點已經被訪問過,避免路徑產生迴路,從而產生死循環
q.push_back(Point(i-1, j));
dfs(i-1, j);
q.pop_back();
//path[i-1][j]=0;
}
if(i<N-1 && 1!=maze[i+1][j] && 1!=path[i+1][j])
{
path[i+1][j]=1;
q.push_back(Point(i+1, j));
dfs(i+1, j);
q.pop_back();
//path[i+1][j]=0;
}
if(j>0 && 1!=maze[i][j-1] && 1!=path[i][j-1])
{
path[i][j-1]=1;
q.push_back(Point(i, j-1));
dfs(i, j-1);
q.pop_back();
//path[i][j-1]=0;
}
if(j<N-1 && 1!=maze[i][j+1] && 1!=path[i][j+1])
{
path[i][j+1]=1;
q.push_back(Point(i, j+1));
dfs(i, j+1);
q.pop_back();
//path[i][j+1]=0;
}
path[i][j]=0;// 擦除訪問痕跡
}