迷宫问题 :
其中要使用栈 栈的定义和基本操作 : 传送门 https://blog.csdn.net/ds19980228/article/details/81741617
简单迷宫 :
0 0 0 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 1 1 0
0 0 1 0 1 1
0 0 1 0 0 0
简单迷宫 (如上图所示 ) : 当我们找出它的通路时, 可以直接利用栈的性质, 从起点开始将所走的路径以下标的方式存入栈, 并且将原来坐标所存的值标记为2, 证明已经走过, 那么周围没有路径可走时, 将栈顶坐标出栈, 再次寻找可走路径, 当栈为空或者达到定义的出口时结束 .这种方法称作回溯法 ( 走完之后如下图所示 )
简单迷宫 :
0 0 0 0 0 0
0 0 2 0 0 0
0 0 2 0 0 0
0 0 2 2 2 0
0 0 2 0 2 2
0 0 2 0 0 0
上面是简单迷宫的处理方法, 那如果迷宫复杂一点的话( 如下图所示 )那又该如何处理呢 ?
多通路迷宫 : 通路间不带环
0 0 0 0 0 0
0 1 1 1 1 1
0 1 0 0 0 0
0 1 0 0 0 0
0 1 1 1 1 1
0 1 0 0 0 0
多通路迷宫 : 通路带环
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 ;
然后判断是否可以通行的条件就变为 :
- 当下一个坐标的值为 1 可以通行
- 当下一个坐标的值比当前坐标值大于 2 可以通行
- 当无路可走且栈不为空时, 出栈 , 栈为空时结束
若要求出最小的路径只需要将每次到出口时的路径求出, 并且与下次新出口的路径进行比较, 保持路径最小
演示 :
第一遍走 : 第二遍走
0 0 0 0 0 0 0 0 0 0 0 0
0 6 7 8 0 0 0 6 7 8 0 0
0 5 0 9 0 0 0 5 0 7 0 0
0 4 0 10 0 0 0 4 0 6 0 0
0 3 12 11 12 13 0 3 4 5 6 7
0 2 0 0 0 0 0 2 0 0 0 0
代码如下 :
//检查是否有通路
int CheckAccess(Pos next,Pos cur)
{
//判断是否有通路的条件
if ((next._col > 0 && next._col<N&&next._row>0 && next._row < N) &&
(maze[next._row][next._col] == 1 || maze[next._row][next._col] > maze[cur._row][cur._col] + 1))
return 1;
else
return 0;
}
//寻找最短通路
void MazeGetShortPath(Pos entry)
{
int i, j;
int arr[N][N] = {0};
Stack path;
Pos cur;
Pos next;
int len = 0;
StackInit(&path);
StackPush(&path, entry);
cur = StackTop(&path);
maze[cur._row][cur._col] = 2;
while (StackEmpty(&path))
{
cur = StackTop(&path);
//当找到出口时,求出路径长度
if (cur._col == 5)
{
//如果旧路径小于新路径或者len为0时,则更新len的大小,并且用两个辅助栈
//记录该路径所走的路线
if (len == 0 || len > StackSize(&path))
{
Stack back;
Stack Path;
len = StackSize(&path);
StackInit(&Path);
StackInit(&back);
//将最短路径所走的路线存在Path里边
while (StackEmpty(&path))
{
StackPush(&back, StackTop(&path));
StackPush(&Path, StackTop(&path));
StackPop(&path);
}
//还原原始栈
while (StackEmpty(&back))
{
StackPush(&path, StackTop(&back));
StackPop(&back);
}
}
}
//检查上边是否通路
next = cur;
next._row -= 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
//检查下边是否有通路
next = cur;
next._row += 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
//检查左边是否有通路
next = cur;
next._col -= 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
//检查右边是否有通路
next = cur;
next._col += 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
//若无通路栈顶元素出栈
StackPop(&path);
}
printf("最短路径长度为:%d", len);
printf("\n");
printf("所走路径如下图:");
while (StackEmpty(&Path))
{
arr[StackTop(&Path)._row][StackTop(&Path)._col] = -1;
StackPop(&Path);
}
printf("\n");
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%2d ", arr[i][j]);
printf("\n");
}
}
完整代码 :
栈之前已经实现过, 直接拿来用即可
Maze.h
#pragma once
#define N 6
static int maze[N][N] = { 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 };
//数据结构
typedef struct Pos
{
int _row;
int _col;
}Pos;
//寻找最短路径,并且打印最短路线
void MazeGetShortPath(Pos entry);
//打印迷宫
void PrintMaze()
Maze.c
#include "Maze.h"
//栈的头文件
#include "Stack.h"
//检查是否有通路
int CheckAccess(Pos next,Pos cur)
{
if ((next._col > 0 && next._col<N&&next._row>0 && next._row < N) &&
(maze[next._row][next._col] == 1 || maze[next._row][next._col] > maze[cur._row][cur._col] + 1))
//判断条件
return 1;
else
return 0;
}
//打印迷宫
void PrintMaze()
{
int i, j;
printf("\n");
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%2d ", maze[i][j]);
printf("\n");
}
}
//寻找最短通路
void MazeGetShortPath(Pos entry)
{
int i, j;
int arr[N][N] = {0};
Stack back;
Stack path;
Stack Path;
Pos cur;
Pos next;
int len = 0;
StackInit(&path);
StackPush(&path, entry);
cur = StackTop(&path);
maze[cur._row][cur._col] = 2;
while (StackEmpty(&path))
{
cur = StackTop(&path);
if (cur._col == 5)
{
if (len == 0 || len > StackSize(&path))
{
len = StackSize(&path);
StackInit(&Path);
StackInit(&back);
while (StackEmpty(&path))
{
StackPush(&back, StackTop(&path));
StackPush(&Path, StackTop(&path));
StackPop(&path);
}
while (StackEmpty(&back))
{
StackPush(&path, StackTop(&back));
StackPop(&back);
}
}
}
//检查上边是否通路
next = cur;
next._row -= 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
next = cur;
next._row += 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
next = cur;
next._col -= 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
next = cur;
next._col += 1;
if (CheckAccess(next, cur))
{
StackPush(&path, next);
maze[next._row][next._col] = maze[cur._row][cur._col] + 1;
continue;
}
StackPop(&path);
}
printf("最短路径长度为:%d", len);
printf("\n");
printf("所走路径如下图:");
while (StackEmpty(&Path))
{
arr[StackTop(&Path)._row][StackTop(&Path)._col] = -1;
StackPop(&Path);
}
printf("\n");
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%2d ", arr[i][j]);
printf("\n");
}
}
Test.c
#include "Stack.h"
#include "Maze.h"
int main()
{
Pos entry;
entry._row = 5;
entry._col = 1;
PrintMaze();
printf("\n");
MazeGetShortPath(entry);
PrintMaze();
system("pause");
return 0;
}
调试结果如下 :