迷宫问题
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 61 Accepted Submission(s) : 37
Problem Description
定义一个二维数组:
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0
Sample Output
(0, 0) (1, 0) (2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (3, 4) (4, 4)
Source
PKU
题意:
这道题是让求在一个5*5的矩阵中从左上角到右下角所走的步数最小的路径!
思路:
这道需要用到广搜+并查集来搜索最短的路径,并将其建成一个树状的结构,然后在树稍出就是要找的终点,然后从终点通过递归找树根,找到树根之后将树根输出,然后沿着原来递归来的方向进行输出,直到最终的终点!
在建立树的时候需要将二维数组一位化,然后才能建立树,否则一个y会对应多个x,从而无法一一对应,最终没有输出,一维化之后,那个数对5取余,对5取商都能得到唯一的解,所以要将其一维话,来建立树!
代码:
/*
这个题最坑的就是让找到路径还得输出,这一点为难死了!然后巧妙地利用一个并查集和递归将这个问题给解决了!两个坐标还没办法
用并查集,因此就只能用一个数来对应一个坐标,来将这个问题解决掉,然后就能建立树了,建好树之后要将找到的那一条路径输出,又是一个难题
因此,就应用了一个递归,从终点开始沿着路径找起点,也就是递归查找的过程,然后冲递归回去,就是将数据从找到的起点开始输出
一直到将终点输出为止!
*/
#include <stdio.h>
#include <string.h>
#include <queue>
#define INF 0xfffffff
#include <algorithm>
using namespace std;
int map[6][6];
int vis[6][6];
int x,y,ex,ey;
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};
int ans;
int n,m;
int pre[30];
int c,d;
void init()
{
ans=INF;//保存最小的步数
for(int i=0;i<5;i++)//输入5*5的二维数组(它代表一个迷宫)
for(int j=0;j<5;j++)
{
scanf("%d",&map[i][j]);
}
}
struct node//定义结构体,并且定义一个结构体优先队列
{
int x,y,step;
friend bool operator < (node a,node b)
{
return a.step>b.step;//按步数从小到大排序
}
}a,temp;
void print(int a)//用递归的方法,将路径输出
{
if(a>=0)//0的父节点为-1,为负数,不成立,所以不能往下递归,输出(0,0),继续往前回溯,将其前面的元素逐个输出
{
print(pre[a]);
int x=a/5;int y=a%5;
printf("(%d, %d)\n",x,y);
}
}
int judge()//判断是否符合条件
{
if(temp.x<0||temp.x>=5) return 0;
if(temp.y<0||temp.y>=5) return 0;
if(map[temp.x][temp.y]==1) return 0;
if(vis[temp.x][temp.y]==1) return 0;
if(temp.step>=ans) return 0;
return 1;
}
void bfs()//寻找最短路径,并输出
{
a.x=0;
a.y=0;
a.step=0;
c=0;//变量c用来保存结构体a的x,y元素对应的值(也就是c=x*5+y)
memset(vis,0,sizeof(vis));//将标记数组清零
memset(pre,-1,sizeof(pre));//将父节点都设为-1
vis[0][0]=1;//起点标记一下
priority_queue<node>q;//结构体优先队列
q.push(a);//将数组a放到队列中,为后面寻找它周围的数是否是终点做准备!
while(!q.empty())//如果不为空,循环
{
a=q.top();//将对顶元素取出来,进行查找
c=a.x*5+a.y;//结构体a中x,y对应的值用c来表示
q.pop();//对顶元素出队列
for(int i=0;i<4;i++)//找周围的点
{
temp.x=a.x+dx[i];
temp.y=a.y+dy[i];
temp.step=a.step+1;
d=temp.x*5+temp.y;
if(judge())
{
pre[d]=c;//这个一定不要放到下面的这个if语句的下面,否则24就没有父节点了!就只输出一个(4,4)
if(temp.x==4&&temp.y==4)
{
ans=temp.step;
print(24);
return;
}
vis[temp.x][temp.y]=1;//走过的要进行标记
q.push(temp);//将temp结构体进队列,为面的循环做准备(继续找终点)
}
}
}
}
int main()
{
init();//初始化数据
bfs();//寻找终点,并将路径进行输出
return 0;
}