题目:
东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。
Input:
输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
Output:
输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
Sample Input:
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
Sample Output:
(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)
Hint:
坐标(x, y)表示第x行第y列,行、列的编号从0开始,且以左上角为原点。另外注意,输出中分隔坐标的逗号后面应当有一个空格。
题目分析:
这是一道迷宫问题,该问题可以转换为在一个二维平面直角坐标系中,如何从原点(0,0)到达终点(5,5)。将一个点的坐标(x,y)用结构体point来表示。
要找到最短路线,考虑bfs宽度搜索算法,即利用队列,遍历所有可以通过的点组成的所有路线,找出最短路线并输出。当队列不为空时,取出队列首元素,特判终点是否已到达,若已到达停止搜索。否则从该点向外走,根据方格的特点,向外走无非上下左右四个方向,所以此处用到常量数组dx={0,0,1,-1},dy={1,-1,0,0}来表示该点向外走的所有可能性。然后判断其合法性以及用二维数组vis[ ][ ]判断是否曾经到达,若合法且未曾到达,则该方向可行,将其存入队列内,并用数组pre[ ]记录该方向是哪个点走过来的。
因为题目要求输出所有路线,所以可以考虑利用递归逆序输出pre[ ]的方式。因为(0,0)就是起点,没有前一个点,所以当路线点不为(0,0)的执行递归,否则直接输出(0,0)即可。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
const int maxn=1e3+5;
using namespace std;
struct point//坐标
{
int x;
int y;
};
int a[5][5];//矩阵
bool vis[5][5];//标记是否已到达
point pre[maxn][maxn];//前一个节点
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
queue<point> q;//队列
void bfs()
{
memset(vis,false,sizeof(vis));//初始化为flase
memset(pre,0,sizeof(pre));
point s;
s.x=s.y=0;//起始点
q.push(s);
vis[s.x][s.y]=true;
while(!q.empty())//当队列不为空时
{
point temp=q.front();//取出队列首元素
q.pop();
if(temp.x==4 && temp.y==4)//到达终点
{
return ;
}
for(int i=0;i<4;i++) //向外走
{
point next;
next.x=temp.x+dx[i];
next.y=temp.y+dy[i];
if(next.x>=0&&next.x<=4&&next.y>=0&&next.y<=4&&!vis[next.x] [next.y]&&a[next.x][next.y]!=1)
{
vis[next.x][next.y]=true;//被标记为已访问
pre[next.x][next.y]=temp;//前一个点
q.push(next);
}
}
}
}
void output(point t)//递归输出
{
if(t.x!=0||t.y!=0)
{
output(pre[t.x][t.y]);
cout<<"("<<t.x<<", "<<t.y<<")"<<endl;
}
else
{
cout<<"("<<0<<", "<<0<<")"<<endl;
return;
}
}
int main()
{
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
cin>>a[i][j];
}
}
bfs();
point t;
t.x=t.y=4;
output(t);
return 0;
}