蓝桥杯2019初赛]迷宫(dfs版本)

传送门

大意:
题目的意思还是模板的搜索,不同的是我们要记录路径了,而且是最短字典序最小的路径。

思路:
1、对于字典序最小,也就是说我们要尽量先往下走,然后是左…
这个很简单,因为在dfs中是顺序枚举,所以我们这样
b[5]={0,1,0,0,-1}//控制X坐标
c[5]={0,0,-1,1,0};//控制Y坐标
2、记录路径。开一个一维数组VV,向下走记为1,向左为2…。
3、每次到达终点时判断是否是当前的最短路径。是的话把路径转换为字符串存起来(覆盖掉原来存的),否则没用。

注意事项
1、使用vis标记走过的点时要把起点提前设置为1,我在这里浪费了好多时间。。。。。
2、在剪枝时不能dp[nx][ny]<=steps+1,不能有等号

	if(steps+1>dp[nx][ny])		return;

如果等于也return,可能前一次更新时并没有走到终点,这么剪枝就是错误的。

剪枝
对于30*50的矩阵,不剪枝还用什么dfs???
1、搜索过程中如果步数大于已走的最小步数,return。
2、起始也就是1的升级版。对于每个点,我们都存起先前到达的最短步数在dp数组中,如果当前步数加1大于了先前保留的值,则没有必要走下去,否则更新dp数组。

蟹蟹dalao观摩%%%%%%%!!!

代码

#include <bits/stdc++.h>
using namespace std;
int vis[50][100];
int a[50][100];
string ss;
int minn=9999999;
int b[5]={0,1,0,0,-1},c[5]={0,0,-1,1,0};
char s[10];
int vv[2000];
int dp[50][100];
void dfs(int x,int y,int steps)
{
	if(steps>minn)	return;
	if(x==30&&y==50)
	{
		if(steps<minn)
		{
			minn=steps;
			string temp;
			for(int i=1;i<=steps-1;i++)
				temp+=s[vv[i]];
			ss=temp;	
		}
		return;
	}
	for(int i=1;i<=4;i++)
	{
		int nx=x+b[i],ny=y+c[i];
		if(nx<1||ny<1||nx>30||ny>50)	continue;
		if(a[nx][ny]==1||vis[nx][ny])	continue;
		if(steps+1>dp[nx][ny])		return;
		dp[nx][ny]=steps+1;
		vv[steps]=i;
		vis[nx][ny]=1;
		dfs(nx,ny,steps+1);
		vis[nx][ny]=0;
	}
}
int main()
{
	for(int i=0;i<=40;i++)
	{
		for(int j=1;j<=60;j++)
			dp[i][j]=9999999;//初始化 
	}
	for(int i=1;i<=30;i++)
	{
		for(int j=1;j<=50;j++)
		{
			a[i][j]=(getchar()-'0');
		}
		getchar();
	}
	s[1]='D',s[2]='L',s[3]='R',s[4]='U';
	vis[1][1]=1;//记得起点标记 
	dfs(1,1,1);
	cout<<ss;
//	cout<<"DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR";
}
posted @ 2020-01-24 00:06  倾叶子佮  阅读(617)  评论(1编辑  收藏  举报