题意:
左上角是迷宫入口,右下角是迷宫出口,寻找从入口到出口的最短路径并输出最短路径。
输入:
输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
输出:
输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
输入样例:
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0
输出样例:
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(3, 2)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)
思路分析:
本题目是典型的迷宫类问题,要求找到最短路径并输出。采用BFS算法从起点进行遍历直到找到到终点的最短路径。类似于树的层次遍历。需要一个bool类型数组记录每一个点是否已访问过。可以用int类型二维数组或者给点类型结构体增加一个int类型元素的方式来记录到各点的最短路径的距离。从初始点开始访问,将其标记为已访问过并入队列,然后依次从队列中取出每一个点访问每一个未被访问过但可到达的邻接点,并均标记为已访问过,将这些点加入到队列中去,以此类推直到到达终点或者所有从起点可达的顶点均被访问过。
注意事项:
1、本题目要求以坐标的形式输出路径,可使用递归输出,但为防止递归栈溢出,一般采用vector或stack来存储路径然后输出。
2、增加常量数组d[x][y]={{1,0},{-1,0},{0,1},{0,-1}};或者d[x]={1,-1,0,0};d[y]={0,0,1,-1};可以更方便访问一个顶点的四个方向的邻接点。
3、bool类型的vis数组其实可以省略掉,记录最短距离长度的int类型dis数组在最开始时可用memset函数赋初值为-1,之后只要某一个点的dis值小于0,则代表未被访问过,对其dis值更新为最短距离长度,此时大于0,则表示已经访问过该点。
参考代码:
#include <bits/stdc++.h>
using namespace std;
struct point{
int x,y;
point(int a=0,int b=0):x(a),y(b){}
};
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int maze[5][5];
bool vis[5][5];
int dis[5][5];
const int tx=4;
const int ty=4;
int main(int argc, const char * argv[]) {
// memset(dis, 0, sizeof(dis));
int dis_min=0;
for (int i=0; i<5; i++)
for(int j=0;j<5;j++)
cin>>maze[i][j];
queue<point> q;
q.push(point(0,0));
vis[0][0]=true;
while (!q.empty()) {
point now=q.front();
q.pop();
if(now.x==tx&&now.y==ty)
{dis_min=dis[now.x][now.y];break;}
for (int i=0; i<4; i++) {
int nx=now.x+dx[i];
int ny=now.y+dy[i];
if(!vis[nx][ny]&&maze[nx][ny]==0&&nx>=0&&ny>=0&&nx<=4&&ny<=4)
{
vis[nx][ny]=true;
dis[nx][ny]=dis[now.x][now.y]+1;
q.push(point(nx,ny));
}
}
}
vector<point> vec;//输出最短路径也可以用stack来实现
vec.push_back(point(tx,ty));
dis_min--;
while (dis_min>0) {
point p=vec.back();
for (int i=0; i<4; i++) {
int nx=p.x+dx[i];
int ny=p.y+dy[i];
if(dis[nx][ny]==dis_min)
{
vec.push_back(point(nx,ny));
}
}
dis_min--;
}
cout<<"("<<0<<", "<<0<<")"<<endl;
while (!vec.empty()) {
cout<<"("<<vec.back().x<<", "<<vec.back().y<<")"<<endl;
vec.pop_back();
}
return 0;
}