poj 3984 迷宫问题【bfs+输出路径】

迷宫问题

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)
Total Submission(s) : 61   Accepted Submission(s) : 37
Problem Description
定义一个二维数组:
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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值