蓝桥杯刷题——迷宫(搜索)

314 阅读2分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

这是蓝桥杯2019年省赛的一道题目,是一道很传统的迷宫题目,给出的数据规模并不大。考察考生的深度优先搜索算法。但是也有一定的难点。

题目

给定一个平面的迷宫,从最左上入口进入,从最右小出口出去。迷宫是有障碍的,1表示障碍,0则表示可通行。从入口开始,往下走记为D,往上走记为U,往左走记为L,往右走记为R。到终点时,要求输出最短的路径,并且路线的字典序也要最小。例如000走出去就是RR。迷宫如下图:

image.png

思路

很明显我们可以使用深度优先搜索,但是题目要求输出最短路径,并且还是一串字符串。这里就是一个难点。我们要怎么解决这个问题呢?我们可以记录每个点从起点到达这个点时最短需要几步。这样可以很容易的求出最短路径需要几步,但是我们还是没有解决输出最短路径的问题。我们只需使用一个标记数组,标记每次走到这个点时如何走过来的就可以了。从起点走到终点的路线直接遍历这个数组就可以得出答案了。每次递归之后都会回溯一次的,标记函数会被覆盖,不需要担心标记函数会标错。每次到达终点直接比较一下所需步数以及字典序就可以得到最短以及字典序最小的路径。

代码

#include<bits/stdc++.h>
using namespace std;
int tem[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
char s[5]={'U','D','L','R'};
int mig[60][60],mins[60][60];
char biao[2000];
int min;
string ans;
bool judge(int x,int y) {//判断这个点是否越界,是否走过。
	if(x>0&&x<=30&&y>0&&y<=50&&!mig[x][y])
		return true;
	return false;
}
void dfs(int x,int y,int pos) {
	if(pos>min)
		return ;
	if(x==30&&y==50) {
		string temp;
			for(int i=1;i<pos;i++)
				temp+=biao[i];
		if(pos<min) {//是最短的路
			ans=temp;
			min=pos;
		}
		else if(pos==min&&temp<ans)	ans=temp;//字典序要最小
		return ;
	}
	for(int i=0;i<4;i++) {
		int x1=x+tem[i][0];
		int y1=y+tem[i][1];
		if(judge(x1,y1)&&pos+1<=mins[x1][y1]) {
			mig[x1][y1]=1;
			mins[x1][y1]=pos+1;
			biao[pos]=s[i];
			dfs(x1,y1,pos+1);
			mig[x1][y1]=0;//回溯找短的路,或者时字典序最小的。
		}
	}
}
int main()
{
	memset(mins,127,sizeof(mins));//取127是mins数组全部数取了int的最大值,有兴趣可去了解这个函数。
	best=1000000;
	for(int i=1;i<=30;i++)
		for(int j=1;j<=50;j++) {
                        char a;
                        cin>>a;
			mig[i][j]=a-'0';//因为输入数据是连着一起的,如果不这样输入将输入不进去。
		}
	mig[1][1]=1;
	dfs(1,1,1);
	cout<<ans<<endl;
	return 0;
}