广搜 -------快走迷宫

题目描述

有一个mn格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这mn个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出最短的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。

优先顺序:左上右下

输入输出格式

输入格式:

第一行是两个数m,n(1<m,n<15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。

输出格式:

字典序最小的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用 “->”表示方向。 如果没有一条可行的路则输出-1。

输入输出样例

输入样例#1:

5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6

输出样例#1:

(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
//快走迷宫 洛谷 
#include <cstdio>
using namespace std;
int n,m;
int c[1000][1000],heng[1000],zong[1000],pre[1000];
int vis[1000][1000];
int head,tail;
int sx,sy,ex,ey,flag  = head = tail = 0;
int dir[4][2] = { {0,-1},{-1,0},{0,1},{1,0}};//左上右下 
void print(int f)
{
	if(pre[f]) print(pre[f]);//继续找前面的,知道找到pre为0的,即为f==1的 
	if(f == 1) printf("(%d,%d)" ,heng[f],zong[f]);
	else printf("->(%d,%d)",heng[f],zong[f]);
//	printf("\n");
}
void bfs(int x ,int y)
{
	flag = 0;
	vis[x][y] = 1;
	tail = 1;
	head = 0;
	heng[tail] = x , zong[tail] = y , pre[tail] = 0;
	while(head != tail)
	{
		head ++;//新的起始点 
		//printf("%d\n",head);
		for(int k =0; k < 4;k ++)//沿四个方向 开始走
		{
			int xx = heng[head] + dir[k][0];
			int yy = zong[head] + dir[k][1];
			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m)//限制不能超出棋盘大小 
			{
				if(!vis[xx][yy])
				{
					vis[xx][yy] = 1;
					tail ++;//将所有符合条件的都放入队列中, 
				//	printf("%d\n",tail);
					heng[tail] = xx, zong[tail] = yy ,pre[tail] = head;
					if(xx == ex && yy == ey) 
					{
						flag = 1;
						print(tail);//从最尾端开始看,找最原始的哪一个点,然后输出 
						break;//打破for循环 
					}
					//如果没到,那么继续进行for循环,知道结束,若结束还没有找到,==没有一条路径 
				}
			}
		}
		if(flag) break; 
	}
}
int main()
{
	
	scanf("%d%d",&n,&m);//n为行,m为列 
	for(int i = 1; i <= n;i++)
		for(int j =1; j <= m;j++)
		{
			scanf("%d",&c[i][j]); 
			if(c[i][j] == 0) vis[i][j] = 1;//0代表不能走,所以这个点 不能在进行占领 
		}
	scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
	bfs(sx,sy);
	if(flag == 0) printf("-1\n");
	return 0;
} 

思路解析:

迷宫里最短路径问题:要用广搜 --- 很好理解:eg.先从起点开始走,先看周围一圈有没有终点,如果有的话,那么直接走到终点。

广搜(bfs)难点:要用一个head , tail 来表示现在遍历到哪了,head 表示节点,tail 表示扩展点。

1、先将head ,tail ,pre 要初始化,因为要输出,所以用一个前驱数组pre[100]记录一下移动之前的那个head(节点)。

2、使用while 循环,当这个队列中有东西的时候才开始进行(head != tail)head的初始值为0,要将head++ 变为现有的tail,然后这个点进行扩展,现在的这个点不可以超出棋盘的范围,但也不可以是0(0代表不能走),先对一个点的扩展点进行搜索,若都不是终点,那么要将每一个扩张点变为新的head(节点),再进行扩展,要将扩展点都放入队列之中,所以 tail要 ++并改记录这个点的前驱(作为标记,方便之后的输出),两个数组分别记录走到的点的横纵坐标,同时表示这个点已经被占领了。

3、如果现在这个点已经是终点了,那么就需要打印(方法比较特殊),并且立一个flag 表示可以找到一条路径。

4、print()打印的函数:输出迷宫的路径要从头到尾,但我们要输出的时候,最后一个点是终点,所以用pre数组记录之前的点的标号(head++相当于给每一个节点标了号),当pre数组所代表的数为1时,说明这个点是起点,从这个数组开始输出。

注意:1、这个print函数是一个递归函数,(1)先找起点(2)找到起点之后,输出起点(3)输出起点之后退出一层循环,再继续输出,知道结束。(所以格式腰围 if if else)

2、行走的方向要注意行和列:向左或向右时,行不变,列变,即x不变,y变

向上或向下时,行变,列不变,即x变,y不变

猜你喜欢

转载自blog.csdn.net/xx1257gd/article/details/82112683
今日推荐