棧的應用 —— 迷宮問題
阿新 • • 發佈:2019-01-27
題目
這是幾個由二維陣列構成的迷宮,簡單的迷宮,多通路不帶環的迷宮,多通路帶環的迷宮!對於簡單迷宮我們需要判斷是否有出口!對於多通路不帶環的迷宮我們需要確定出口並且判斷最短路徑,對於通路間帶環的迷宮我們需要找出最短路徑!
演算法思想:回溯
回溯演算法實際上一個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。
在本題中也用到的就是回溯, 就是把走過的點座標壓棧,遇到無路可走的情況就開始回溯,也就是出棧!
總體思路就是:
- 現將入口點壓棧,走過的地方標記為2
- 每走一步就將座標壓棧,判斷下一步可以走的地方,如果能走就壓棧
- 當上下左右四個方向都不能走的時候就回溯
- 直到回溯到入口點還是沒有其他方向可以走,那麼迴圈結束,也就意味著沒有出口!
- 使用一個方法判斷座標點是否合法的,注意陣列越界的情況,首先不越界,其次座標點值為1的時候才是合法的
- 對於多通路迷宮首先需要明白當右邊出現兩個入口點的時候只需要判斷
列 == N
即可認為是找到了出口 - 首先下一個點可以走的條件是:該點值為1或者該點值比上一個+1還大
- 每走一步值就+1,入口點值設定為2
程式碼
int CheckAccess(Pos next)
{
//判斷越界的情況
if(next._col >= 0 &&next._row>=0
&& next._col<N && next._row<N)
{
//1才是表示通路
if (maze[next._row][next._col] == 1)
{
return 1;
}
}
//return 0表示不可以通過
return 0;
}
int MazeGetPath(Pos entry,Pos exit)
{
Pos cur = entry;//cur記錄起始位置
Stack path;
StackInit(&path);
StackPush(&path, entry);//將起始座標壓棧
while (StackEmpty(&path))
{
cur = StackTop(&path);
if ((cur._row == exit._row) && (cur._col == exit._col))
return 1;
//探測下一次可以去的地方
maze[cur._row][cur._col] = 2;//標記上一次走過的位置
//上
Pos next = cur;
next._row -= 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//回溯
StackPop(&path);
}
return 0;
}
對於稍複雜的迷宮的核心程式碼
int CheckAccess(Pos next)
{
//判斷越界的情況
if(next._col >= 0 &&next._row>=0
&& next._col<N && next._row<N)
{
//1才是表示通路
if (maze[next._row][next._col] == 1)
{
return 1;
}
}
//return 0表示不可以通過
return 0;
}
int MazeCheckIsAccess(Pos cur, Pos next)
{
//判斷越界的情況
if ((next._col >= 0 && next._row >= 0 && next._col<N && next._row<N)
&&(maze[next._row][next._col] == 1 || maze[next._row][next._col]>maze[cur._row][cur._col]+1))
{
return 1;
}
//return 0表示不可以通過
return 0;
}
int pathsize = 0;
int MazeGetPath(Pos entry,Pos exit)
{
Pos cur = entry;//cur記錄起始位置
Stack path;
StackInit(&path);
StackPush(&path, entry);//將起始座標壓棧
maze[entry._row][entry._col] = 2;
while (StackEmpty(&path))
{
cur = StackTop(&path);
maze[cur._row][cur._col] = 2;//標記上一次走過的位置
//if ((cur._row == exit._row) && (cur._col == exit._col))
if (cur._col == 5)
{
//如果只找一條通路則返回
//return 1;
//StackDestory(&path);
if (pathsize == 0||
StackSize(&path) < pathsize)
{
pathsize = StackSize(&path);
}
}
//探測下一次可以去的地方
//上
Pos next = cur;
next._row -= 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
StackPush(&path, next);
continue;
}
//回溯
StackPop(&path);
}
return 0;
}
int MazeGetShortPath(Pos entry, Pos exit)
{
Pos cur = entry;//cur記錄起始位置
Stack path;
StackInit(&path);
StackPush(&path, entry);//將起始座標壓棧
maze[entry._row][entry._col] = 2;
while (StackEmpty(&path))
{
cur = StackTop(&path);
if (cur._col == 5)
{
//如果只找一條通路則返回
//return 1;
//StackDestory(&path);
if (pathsize == 0 ||
StackSize(&path) < pathsize)
{
pathsize = StackSize(&path);
}
}
//探測下一次可以去的地方
//上
Pos next = cur;
next._row -= 1;
if (MazeCheckIsAccess(cur, next))
{
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
StackPush(&path, next);
continue;
}
//下
next = cur;
next._row += 1;
if (MazeCheckIsAccess(cur, next))
{
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
StackPush(&path, next);
continue;
}
//左
next = cur;
next._col -= 1;
if (MazeCheckIsAccess(cur, next))
{
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
StackPush(&path, next);
continue;
}
//右
next = cur;
next._col += 1;
if (MazeCheckIsAccess(cur, next))
{
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
StackPush(&path, next);
continue;
}
//回溯
StackPop(&path);
}
return 0;
}