Description
以一个M×N的长方阵表示迷宫。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的最佳通路。
实验目的:继续熟练掌握栈的特点;灵活应用栈和队列。
具体要求:
(1)以一个M×N的长方阵表示迷宫,1和0分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的最佳通路,或得出没有通路的结论。(所谓最佳通路是指在所有的通路中输出步长最短的一条通路。)
(2)首先创建一个迷宫,输入格式为:M N,指定迷宫的行数和列数,然后按行输入迷宫的每一行的布局信息(参见输入示例)。求得的通路以三元组(i, j, d)的形式输出(每行输出5组),其中:(i, j)表示迷宫的坐标,d表示走到下一坐标的方向(值为1、2、3、4,分别对应右、下、左、上方向)。迷宫入口坐标(左上角)为(1,1),出口坐标为右下角(M,N),若有通路,则最后输出的坐标三元组格式为(M,N,0)。
(3) 本题目要求可以连续输入多组迷宫数据进行测试,若输入迷宫的行数和列数分别为0,则输入结束。注意输出格式的要求。
(4)提示:用栈和队列都可实现。使用栈从所有可能的通路中寻找最短路径。使用队列可通过广度优先算法直接确定最短路径。
Input
示例输入:
4 5 ----------迷宫的行数和列数
1 0 0 0 0
1 1 1 0 1
1 0 0 1 1
1 1 1 1 1
4 4 ----------迷宫的行数和列数
1 0 0 1
1 0 1 1
1 0 0 1
1 0 1 1
0 0 ----------输入结束标志
Output
若迷宫有通路,则输出迷宫的通路,以每行输出5组的形式控制输出格式;若迷宫没有通路则输出“没有通路”。如上例的输入对应的输出为:
(1,1,2)(2,1,2)(3,1,2)(4,1,1)(4,2,1)
(4,3,1)(4,4,1)(4,5,0)
没有通路
Sample Input
<span style="color:#333333"><span style="background-color:#f5f5f5">4 5
1 0 0 0 0
1 1 1 0 1
1 0 0 1 1
1 1 1 1 1
4 4
1 0 0 1
1 0 1 1
1 0 0 1
1 0 1 1
0 0</span></span>
Sample Output
<span style="color:#333333"><span style="background-color:#f5f5f5">(1,1,2)(2,1,2)(3,1,2)(4,1,1)(4,2,1)
(4,3,1)(4,4,1)(4,5,0)
没有通路</span></span>
解答如下:
采用广搜法
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
using
namespace
std;
struct
Cell
{
int
row;
int
col;
int
direction;
Cell(
int
r,
int
c,
int
d)
{
row = r;
col = c;
direction = d;
}
};
const
int
dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
// 检查是否是有效的移动位置
bool
valid(
int
row,
int
col,
int
x,
int
y,
const
vector<vector<
int
>>& maze)
{
return
(row >= 0 && row < x&& col >= 0 && col < y&& maze[row][col] == 1);
}
// 寻找从起点到终点的最短路径
vector<Cell> best(
const
vector<vector<
int
>>& maze,
int
x,
int
y)
{
vector<vector<
bool
>> visited(x, vector<
bool
>(y,
false
));
// 记录单元格是否被访问过
vector<vector<Cell>> prev(x, vector<Cell>(y, Cell(-1, -1, -1)));
// 记录单元格的前一个单元格信息
queue<Cell> q;
// 存储待访问的单元格
q.push(Cell(0, 0, -1));
// 起点入队
visited[0][0] =
true
;
// 标记起点为已访问
while
(!q.empty())
{
Cell current = q.front();
q.pop();
int
row = current.row;
int
col = current.col;
int
direction = current.direction;
if
(row == x - 1 && col == y - 1)
{
// 找到终点,重构路径并返回
vector<Cell> path;
while
(row != -1 && col != -1)
{
if
(direction != -1)
{
path.push_back(Cell(row + 1, col + 1, direction));
}
int
newRow = prev[row][col].row;
int
newCol = prev[row][col].col;
direction = prev[row][col].direction;
row = newRow;
col = newCol;
}
reverse(path.begin(), path.end());
return
path;
}
for
(
int
i = 0; i < 4; i++)
{
int
newRow = row + dir[i][0];
int
newCol = col + dir[i][1];
if
(valid(newRow, newCol, x, y, maze) && !visited[newRow][newCol])
{
q.push(Cell(newRow, newCol, i + 1));
// 将相邻单元格加入队列
visited[newRow][newCol] =
true
;
// 标记相邻单元格为已访问
prev[newRow][newCol] = Cell(row, col, i + 1);
// 记录相邻单元格的前一个单元格信息
}
}
}
// 未找到路径
return
vector<Cell>();
}
// 打印路径
void
print(
const
vector<Cell>& path,
int
x,
int
y)
{
if
(path.empty())
{
cout <<
"没有通路"
<< endl;
return
;
}
for
(
size_t
i = 0; i < path.size(); i++)
{
if
(path[i].row == x && path[i].col == y)
{
cout <<
"("
<< path[i].row <<
","
<< path[i].col <<
","
<<
"0"
<<
")"
;
}
else
{
cout <<
"("
<< path[i].row <<
","
<< path[i].col <<
","
<< path[i].direction <<
")"
;
}
if
((i + 1) % 5 == 0)
{
cout << endl;
}
/*else
{
cout << " ";
}*/
}
cout << endl;
}
int
main()
{
int
x, y;
while
(cin >> x >> y && (x != 0 || y != 0))
{
vector<vector<
int
>> maze(x, vector<
int
>(y));
if
(x == 1 && y == 1)
{
cin >> maze[0][0];
if
(maze[0][0] == 1)
{
cout <<
"("
<<
"1"
<<
", "
<<
"1"
<<
", "
<<
"0"
<<
")"
;
}
else
cout <<
"没有通路"
;
}
else
{
for
(
int
i = 0; i < x; i++)
{
for
(
int
j = 0; j < y; j++)
{
cin >> maze[i][j];
}
}
vector<Cell> path = best(maze, x, y);
print(path, x, y);
}
}
return
0;
}