给定一个迷宫,0表示空地可以走,1表示墙壁不能穿越;在迷宫中可以向(上下左右)四个方向行进;
找到从左上角到右下角的最短路径,并计算最短路径的长度。
迷宫示例如下:
算法步骤:
- 1、从起始点出发,遍历四个方向,如果某个方向可以走,则先存储起来;
- 2、按照四个方向中可以走网格进行尝试,如果该网格的四个方向仍可以走,则存储起来。
- 3、直至到达网格的右下角,停止搜索。
从以上分析可以看出,该步骤是按照一个广度优先搜索的方式进行的,而广度优先搜索讲究的是先访问的亦先被访问。因此使用队列存储当前步骤下可以走的网格,并对可以走的网格进行上述的迭代。
由于我们需要求得左上角到右下角的最短路径,那么我们可以使用一个二维数组标记从哪个方向到达的当前网格(且可以通过该二维数组确认当前网格是否已经被访问,如果被访问过,则无需再次访问,因此第一次访问的就是最短的),最终通过从终点到起点的逆序搜索,即可得到最短的逆序路径。
使用栈存储该路径,最终栈的大小即为路径长度,出栈的序列即为最短路径序列;
void minPathBFS(vector<vector<int>> &maze) {
//maze矩阵中,0表示可走,1表示墙不可走
int rows = maze.size();
int cols = maze[0].size();
queue<pair<int, int>> poss;//存放当前可访问位置,先访问亦先被访问
vector<vector<int>> visited(rows, vector<int>(cols));
//记录从哪个方向到达当前该网格,默认-1为起点,0为没有走的默认值,1向上,2向下,3向左,4向右
int jump[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };//上下左右的跳跃方式
pair<int, int> start(0, 0);
poss.push(start);
visited[0][0] = -1;
while (!poss.empty()){
int x = poss.front().first;
int y = poss.front().second;
poss.pop();
if (x == rows - 1 && y == cols - 1){
break;
}
//遍历四个方向,如果有可以走的,先将可走的位置放在队列中,如果到达了终点,则直接break
for (int i = 0; i < 4; i++){
int newX = x + jump[i][0];
int newY = y + jump[i][1];
//矩阵边界范围内,不是墙,且未被访问过
if (newX >= 0 && newX < rows && newY >= 0 && newY < cols && maze[newX][newY] == 0 && visited[newX][newY] == 0){
poss.push(pair<int, int>{newX, newY});
visited[newX][newY] = i + 1;//标记从哪个方向过来
}
}
}
//根据历史路径矩阵画出原始路径
int stX = rows-1, stY = cols-1;
if (visited[stX][stY] == 0){
cout << "不存在从左上角到右下角的路线" << endl;
//return;
}
//由于从终点到起点是逆序的,因此需要使用栈进行存储
stack<pair<int, int>> path;
path.push(pair<int, int>{stX, stY});
//存在这条路径的话,一定可以从右下角走到左上角
while (stX!=0 || stY!=0){
int aX = stX - jump[visited[stX][stY]-1][0];
int aY = stY - jump[visited[stX][stY]-1][1];
path.push(pair<int, int>{aX, aY});
stX = aX; stY = aY;//更新当前位置
}
int pathLens = path.size();
cout << "最短路径长度为:" << pathLens << endl;
while (!path.empty()){
cout <<"[" <<path.top().first << "," << path.top().second <<"]"<< endl;
path.pop();
}
}