题目链接
题目大意
给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走。
(1)输出沿着左边墙从起点走到终点经过的格数
(2)输出沿着右边墙从起点走到终点经过的格数
(3)起到到终点的最短路
分析
这是一道练习搜索的好题。
1.对于沿着某一边墙走:
用dfs来实现,以沿左边墙为例分析:
如何保证我们的路径一直是沿着左边墙走呢?对于每一个状态,我们要按向左走、向前走、向右走、向后走的优先次序往下一个状态转移,即:能向左走就向左走,不能就向前走,再不能就向右走,再不能就向后走。这里的前后左右是一个相对的概念,由人的朝向决定,因此,我们在dfs时需要维护一个代表朝向的参数。
我按以下的方式定义朝向:
假设当前位置下我面朝1,(即上一步我是从3走过来的),我的搜索顺序应该为2103(从左手边开始顺时针转)
沿着右边的墙走同理。
由于不是求最短路,格子可以重复走,因此不需要标记数组。
2.对于求迷宫最短路
只能用BFS,层层扩展,队尾元素的步数是队首元素步数+1.
本题还是要注意字符地图的输入。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 41
using namespace std;
struct Node
{
int x,y,step;
};
char maze[MAXN][MAXN];
int n,m,l_step,r_step,sp_step;
bool vis[MAXN][MAXN],l_flag,r_flag,sp_flag;
bool can(int x,int y)
{
if (1<=x&&x<=n&&1<=y&&y<=m&&maze[x][y]!='#')
return true;
return false;
}
void DFS_LF(int x,int y,int d)//x,y表示坐标,d表示朝向
{
if (l_flag) return;
l_step++;
if (maze[x][y]=='E')
{
l_flag=true;
return;
}
switch (d)
{
case 0:///1032
{
if (can(x,y-1))
DFS_LF(x,y-1,1);
else if (can(x-1,y))
DFS_LF(x-1,y,0);
else if (can(x,y+1))
DFS_LF(x,y+1,3);
else if (can(x+1,y))
DFS_LF(x+1,y,2);
break;
}
case 1:///2103
{
if (can(x+1,y))
DFS_LF(x+1,y,2);
else if (can(x,y-1))
DFS_LF(x,y-1,1);
else if (can(x-1,y))
DFS_LF(x-1,y,0);
else if (can(x,y+1))
DFS_LF(x,y+1,3);
break;
}
case 2:///3210
{
if (can(x,y+1))
DFS_LF(x,y+1,3);
else if (can(x+1,y))
DFS_LF(x+1,y,2);
else if (can(x,y-1))
DFS_LF(x,y-1,1);
else if (can(x-1,y))
DFS_LF(x-1,y,0);
break;
}
case 3:///0321
{
if (can(x-1,y))
DFS_LF(x-1,y,0);
else if (can(x,y+1))
DFS_LF(x,y+1,3);
else if (can(x+1,y))
DFS_LF(x+1,y,2);
else if (can(x,y-1))
DFS_LF(x,y-1,1);
break;
}
}
return;
}
void DFS_RF(int x,int y,int d)
{
if (r_flag) return;
r_step++;
if (maze[x][y]=='E')
{
r_flag=true;
return;
}
switch (d)
{
case 0:///3012
{
if (can(x,y+1))
DFS_RF(x,y+1,3);
else if (can(x-1,y))
DFS_RF(x-1,y,0);
else if (can(x,y-1))
DFS_RF(x,y-1,1);
else if (can(x+1,y))
DFS_RF(x+1,y,2);
break;
}
case 1:///0123
{
if (can(x-1,y))
DFS_RF(x-1,y,0);
else if (can(x,y-1))
DFS_RF(x,y-1,1);
else if (can(x+1,y))
DFS_RF(x+1,y,2);
else if (can(x,y+1))
DFS_RF(x,y+1,3);
break;
}
case 2:///1230
{
if (can(x,y-1))
DFS_RF(x,y-1,1);
else if (can(x+1,y))
DFS_RF(x+1,y,2);
else if (can(x,y+1))
DFS_RF(x,y+1,3);
else if (can(x-1,y))
DFS_RF(x-1,y,0);
break;
}
case 3:///2301
{
if (can(x+1,y))
DFS_RF(x+1,y,2);
else if (can(x,y+1))
DFS_RF(x,y+1,3);
if (can(x-1,y))
DFS_RF(x-1,y,0);
else if (can(x,y-1))
DFS_RF(x,y-1,1);
break;
}
}
return;
}
void BFS_SP(int x,int y)
{
queue<Node> Q;
int next[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
memset(vis,false,sizeof(vis));
Node s;
s.x=x;s.y=y;
s.step=1;
vis[s.x][s.y]=1;
Q.push(s);
while (!Q.empty())
{
Node temp=Q.front();
Q.pop();
for (int i=0;i<=3;i++)
{
Node temp2;
temp2.x=temp.x+next[i][0];
temp2.y=temp.y+next[i][1];
if (can(temp2.x,temp2.y)&&!vis[temp2.x][temp2.y])
{
vis[temp2.x][temp2.y]=true;
temp2.step=temp.step+1;
Q.push(temp2);
if (maze[temp2.x][temp2.y]=='E')
{
sp_step=temp2.step;
return;
}
}
}
}
}
int main()
{
int t,i,j,x,y,direction;
cin>>t;
while (t--)
{
cin>>m>>n;
getchar();
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
{
scanf("%c",&maze[i][j]);
if (maze[i][j]=='S')
{
x=i;y=j;
}
}
getchar();
}
if (x==n)
direction=0; ///朝上
else if (y==m)
direction=1; ///朝左
else if (x==1)
direction=2; ///朝下
else if (y==1)
direction=3; ///朝右
/*左转优先dfs*/
l_step=1;l_flag=false;
switch (direction)
{
case 0:{DFS_LF(x-1,y,0);break;}
case 1:{DFS_LF(x,y-1,1);break;}
case 2:{DFS_LF(x+1,y,2);break;}
case 3:{DFS_LF(x,y+1,3);break;}
}
cout<<l_step<<' ';
/*右转优先dfs*/
r_step=1;r_flag=false;
switch (direction)
{
case 0:{DFS_RF(x-1,y,0);break;}
case 1:{DFS_RF(x,y-1,1);break;}
case 2:{DFS_RF(x+1,y,2);break;}
case 3:{DFS_RF(x,y+1,3);break;}
}
cout<<r_step<<' ';
/*bfs求迷宫最短路*/
BFS_SP(x,y);
cout<<sp_step<<endl;
}
return 0;
}