传送门
大意:
题目的意思还是模板的搜索,不同的是我们要记录路径了,而且是最短字典序最小的路径。
思路:
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";
}