C語言實現簡單迷宮 --- 回溯法(遞迴)
首先我們瞭解一下回溯法。
回溯法:對於一個包括有很多個節點,每個節點由若干個搜尋分支的問題,把原問題分解為若干個子問題求解的演算法;當搜尋到某個節點發現無法再繼續搜尋下去時,就讓搜尋過程回溯(回退)到該節點的前一個結點,繼續搜尋該節點外的其他尚未搜尋的分支;如果發現該節點無法再搜尋下去,就讓搜尋過程回溯到這個節點的前一結點繼續這樣的搜尋過程;這樣的搜尋過程一直進行到搜尋到問題的解或者搜尋完了全部可搜尋分支沒有解存在為止。
迷宮:
0 0 0 0 0 0
0 1 1 1 0 0
0 1 0 1 0 0
0 1 0 1 0 0
0 1 1 1 1 1
0 1 0 0 0 0
思路:
1.傳送迷宮地圖的入口座標,判斷入口座標是否正確。
2.開始走迷宮,
將當前座標(Cur)入棧,準備往某個方向走
上:上走,先判斷上面是否可以走的通,可以就往上走,並修改下一步值為當前值+1;遞迴當前座標,一直往前走,直到不可以往上走
左:上走不通左走,判斷是否可以走,可以就往左走,並修改下一步值為當前值+1;遞迴當前座標,一直往左走,直到不可以往左走
右:左走不通右走,判斷是否可以走,可以就往右走,並修改下一步值為當前值+1;遞迴當前座標,一直往右走,直到不可以往右走,
下:右走不通下走,判斷是否可以走,可以就往下走,並修改下一步值為當前值+1;遞迴當前座標,一直往下走,直到不可以往下走,
3.重複過程2
4.找到出口,不要著急退出可能有兩個出口,所以要退回去找是否還有別的出口,
5.輸出最短路徑
主要用了遞迴的思想,走過的路便不會重複走。並且走過之後所有的值都會變化為>1的數
#define ROW 6
#define COL 6
#define MAX 20
typedef int DataType;
typedef struct postion
{
int _x;
int _y;
}position;
typedef position SDataType;
typedef struct Stack
{
SDataType array[MAX];
int top;
}Stack;
typedef struct Maze
{
DataType _map[ROW][COL];
}Maze;
void InitMaze(int map[ROW][COL],Maze* m);//初始化
void PrintfMaze(Maze* m);//列印迷宮
void PassMaze(Maze* m, SDataType enter);//走迷宮
因為要給棧中壓入座標型別的而資料,所以需要建立一個座標型別的結構體,並用座標型別定義棧的型別。
void InitMaze(int map[ROW][COL],Maze* m)//初始化
{
int i = 0;
int j = 0;
assert(m);
for (; i < ROW; i++)
{
for (j = 0; j < COL; j++)
{
m->_map[i][j] = map[i][j];
}
}
}
void PrintfMaze(Maze* m)//列印迷宮
{
int i = 0;
int j = 0;
assert(m);
for (; i < ROW; i++)
{
for (j = 0; j < COL; j++)
printf("%3d", m->_map[i][j]);
printf("\n");
}
}
int IsValid(SDataType enter)//判斷入口是否正確
{
if (0 == enter._x || 0 == enter._y || ROW - 1 == enter._x || COL - 1 == enter._y)
return 1;
return 0;
}
int IsExit(SDataType Cur,SDataType enter)//判斷是否為出口
{
if ((0 == Cur._x || 0 == Cur._y || ROW - 1 == Cur._x || COL - 1 == Cur._y) && (Cur._x != enter._x || Cur._y != enter._y))
return 1;
return 0;
}
int IsPass(Maze* m, SDataType next)//檢測此路是否通
{
assert(m);
if (next._x < ROW && next._y < COL && next._x >= 0 && next._y >= 0)
{
if (1 == m->_map[next._x][next._y])
return 1;
}
return 0;
}
void SaveShortPath(Stack* Path, Stack* ShortPath)//儲存最短路徑
{
int i = 0;
for (; i < StackSize(Path); i++)
ShortPath->array[i] = Path->array[i];
ShortPath->top = Path->top;
}
void _GetPassMaze(Maze* m, SDataType enter, SDataType Cur, Stack* Path, Stack* ShortPath)//遞迴
{
SDataType next;
if (!StackSize(Path))//如果棧為空,說明剛開始將當前位置變為2入棧
m->_map[enter._x][enter._y] = 2;
if (IsExit(Cur, enter))//判斷是否是出口
{
StackPush(Path, Cur);
if (!StackSize(ShortPath) || StackSize(Path) < StackSize(ShortPath))
SaveShortPath(Path, ShortPath);//儲存最短路徑
StackPop(Path);
return;
}
StackPush(Path, Cur);
//上
next = Cur;
next._x -= 1;
if (IsPass(m, next, Cur))//判斷此路是否可以走
{
m->_map[next._x][next._y] = m->_map[Cur._x][Cur._y] + 1;
_GetPassMaze(m, enter, next, Path, ShortPath);
}
//左
next = Cur;
next._y -= 1;
if (IsPass(m, next, Cur))//判斷此路是否可以走
{
m->_map[next._x][next._y] = m->_map[Cur._x][Cur._y] + 1;
_GetPassMaze(m, enter, next, Path, ShortPath);
}
//右
next = Cur;
next._y += 1;
if (IsPass(m, next, Cur))//判斷此路是否可以走
{
m->_map[next._x][next._y] = m->_map[Cur._x][Cur._y] + 1;
_GetPassMaze(m, enter, next, Path, ShortPath);
}
//下
next = Cur;
next._x += 1;
if (IsPass(m, next, Cur))//判斷此路是否可以走
{
m->_map[next._x][next._y] = m->_map[Cur._x][Cur._y] + 1;
_GetPassMaze(m, enter, next, Path, ShortPath);
}
StackPop(Path);
}
void PassMaze(Maze* m, SDataType enter)
{
Stack ShortPath;
Stack Path;
assert(m);
InitStack(&Path);
InitStack(&ShortPath);
if (!IsValid(enter))
return;
_GetPassMaze(m, enter, enter, &Path, &ShortPath);//呼叫遞迴函式,走迷宮
}
void Test()//測試函式
{
SDataType enter;
Maze m;
int map[ROW][COL] = { 0,0,0,0,0,0,
0,0,1,0,0,0,
0,0,1,0,0,0,
0,0,1,0,0,0,
0,0,1,1,1,1,
0,0,1,0,0,0 };
InitMaze(map,&m);
PrintfMaze(&m);
printf("\n");
enter._x = 5;
enter._y = 2;
PassMaze(&m, enter);
PrintfMaze(&m);
}
上面這段程式碼有幾個棧的基本函式沒有給,可以自己完善呼叫。