题目描述
迷宫是一个二维矩阵,其中1为墙,0为路,入口在第一列,出口在最后一列。
要求从入口开始,从出口结束,按照 上,下,左,右 的顺序来搜索路径.并且求出最短路径。
思想
用回溯法,另外递归是天然的回溯法。
下面是具体的实现代码:
#pragma once
#include <iostream>
#include <stack>
using namespace std;
struct Pos
{
int _row; // 行
int _col; // 列
};
template<size_t M,size_t N>
class Maze
{
public:
Maze(int maze[][N])//二维数组传值必须确定列数,因为二维数组在内存中存储时类似一位数组,一行一行存储
{
for (size_t i = 0; i < M; ++i)
{
for (size_t j = 0; j < N; ++j)
{
_maze[i][j] = maze[i][j];
}
}
}
//Maze(int* maze)
//{
// for (size_t i = 0; i < N; ++i)
// {
// for (size_t j = 0; j < N; ++j)
// {
// _maze[i][j] = maze[i*N+j];
// }
// }
//}
void Print()
{
for (size_t i = 0;i < M; ++i)
{
for (size_t j = 0; j < N; ++j)
{
printf("%d ", _maze[i][j]);
}
cout<<endl;
}
cout<<endl;
}
bool CheckAccess(Pos pos)
{
if (pos._row < N && pos._row >= 0
&& pos._col < N && pos._col >= 0
&& _maze[pos._row][pos._col] == 0)
{
return true;
}
return false;
}
// 栈实现
bool GetPath(Pos entry, stack<Pos>& path)
{
path.push(entry);
while (!path.empty())
{
// 1.入口
// 2.next
// 3.回溯的上一个位置
Pos cur = path.top();
_maze[cur._row][cur._col] = 2;//用2标识走过的路
// 检查是否已经到出口
if(cur._row == N-1)
return true;
// 探测
Pos next = cur;
// 上
next._row -= 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
// 下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
// 左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
// 右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
// 四个方向都走不通,回溯
_maze[cur._row][cur._col] = 3;// 用3标识走不通的路,保证了下次探测时不再走走不通的路
path.pop();
}
return false;
}
// 递归实现
//bool GetPathR(Pos entry, stack<Pos>& path)
//{
// // 返回条件
// // 子问题
// _maze[entry._row][entry._col] = 2;
// if(entry._row == N-1)//返回条件
// return true;
// Pos next = entry;
// // 上
// next._row -= 1;
// if (CheckAccess(next))
// {
// if(GetPathR(next, path))
// return true;
// }
// // 下
// next = entry;
// next._row += 1;
// if (CheckAccess(next))
// {
// if (GetPathR(next, path))
// {
// return true;
// }
// }
// // 左
// next = entry;
// next._col -= 1;
// if (CheckAccess(next))
// {
// if (GetPathR(next, path))
// {
// return true;
// }
// }
// // 右
// next = entry;
// next._col += 1;
// if (CheckAccess(next))
// {
// if (GetPathR(next, path))
// {
// return true;
// }
// }
// _maze[entry._row][entry._col] = 3;
// return false;
//}
bool CheckAccess(Pos cur, Pos next)
{
// 1.检查边界 (next._row >= 0 && next._row < N && next._col >= 0 && next._col < N)
// 2.是否是通路 _maze[next._row][next._col] == 0
// 3.是否自己没走过,但是别人走过,解决带环问题 _maze[next._row][next._col] > _maze[cur._row][cur._col]
if ((next._row >= 0 && next._row < N && next._col >= 0 && next._col < N)
&&( _maze[next._row][next._col] == 0 || _maze[next._row][next._col] > _maze[cur._row][cur._col]))
{
return true;
}
return false;
}
//用递归求最短通路路径
void GetShortPathR(Pos entry, stack<Pos>& path, stack<Pos>& shortPath)
{
// 返回条件
// 子问题
if (!path.empty())
{
Pos prev = path.top();
_maze[entry._row][entry._col] = _maze[prev._row][prev._col]+1;
}
path.push(entry);
if(entry._row == N-1)
{
if (shortPath.empty()
|| path.size() < shortPath.size())
{
Print();
cout<<"当前路径的长度:"<<path.size()<<endl;
cout<<"之前最短路径的长度:"<<shortPath.size()<<endl;
shortPath = path;
}
}
Pos next = entry;
// 上
next._row -= 1;
if (CheckAccess(entry, next))
{
GetShortPathR(next, path, shortPath);
}
// 右
next = entry;
next._col += 1;
if (CheckAccess(entry, next))
{
GetShortPathR(next, path, shortPath);
}
// 下
next = entry;
next._row += 1;
if (CheckAccess(entry, next))
{
GetShortPathR(next, path, shortPath);
}
// 左
next = entry;
next._col -= 1;
if (CheckAccess(entry, next))
{
GetShortPathR(next, path, shortPath);
}
path.pop();
}
protected:
int _maze[M][N];
};
void TestMaze()
{
const size_t M = 10;
const size_t N = 10;
int maze[M][N] = {
{1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1},
{2,0,0,0,0,0,0,1,1,1},
{1,1,0,1,1,1,0,1,1,1},
{1,1,0,0,0,0,0,1,1,1},
{1,1,1,1,1,0,1,1,1,1},
{1,1,1,1,1,0,1,1,1,1},
{1,1,1,1,1,0,1,1,1,1},
{1,1,1,1,1,0,1,1,1,1},
{1,1,1,1,1,0,1,1,1,1}
};
/*int maze[N][N] = {
{1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1},
{0,0,0,1,1,1,1,1,1,1},
{1,1,0,1,1,1,1,1,1,1},
{1,1,0,0,0,0,1,1,1,1},
{1,1,0,1,1,0,1,1,1,1},
{1,1,0,1,1,0,0,0,1,1},
{1,1,0,1,1,0,1,0,1,1},
{1,1,0,1,1,0,1,1,1,1},
{1,1,0,1,1,0,1,1,1,1}
};*/
Maze<M,N> mz(maze);
mz.Print();
Pos entry;
stack<Pos> path;
stack<Pos> shortPath;
entry._row = 2;
entry._col = 0;
mz.GetShortPathR(entry, path, shortPath);
mz.Print();
while (!shortPath.empty())// 打印最短路径
{
Pos pos = shortPath.top();
printf("[%d][%d]\n",pos._row, pos._col);
shortPath.pop();
}
cout<<endl;
}