Description
给定一个迷宫,S是起点,E是终点,’#’是墙不可走,’.’可以走。先输出左转优先时,从S到E的步数;再输出右转优先时,从S到E的步数;最后输出S到E的最短步数
Input
多组用例,第一行为用例组数T,每组用例第一行为两个整数w和h分别表示迷宫宽度和高度,之后为一h*w矩阵表示迷宫
Output
对于每组用例,先输出左转优先时,从S到E的步数;再输出右转优先时,从S到E的步数;最后输出S到E的最短步数
Sample Input
Sample Output
37 5 5
17 17 9
Solution
dfs求左右转优先的步数,bfs求最短步数
因为从起点右转优先到达终点等价于从终点左转优先到达起点,故只需写一个以左转优先的dfs即可,左转优先时必须标记当前位置的方向,下面是我定义的方向
最初的方向由起点S确定,而下一步的方向则由前一步的走向决定
左边优先搜索:
当前位置的方向指向 1(向左)(这同时说明前一步是在3位置走过来的)
那么走下一步时,就要根据2103的顺序,先逐格确定当前位置周边的四格是否可行
若第一次确认2可行,就走到2,在位置2时的方向为2(向下)
若2不可行,则再确定1,若1可行,就走到1,在位置1时的方向为1(向左)
若1也不可行,则再确定0,若0可行,就走到0,在位置0时的方向为0(向上)
若0也不可行,说明进入了迷宫的死胡同,要从原路返回,走回3
根据定义的方向,设当前位置为d,那么左转用数学式子表达就是 d=(d+1)%4
注意:
左边、右边优先搜索都不是找最短路,因此走过的路可以再走,无需标记走过的格
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define maxn 50
int dd[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
bool vis[maxn][maxn];
char map[maxn][maxn];
int sx,sy,ex,ey;
int T,w,h;
int Count,flag;
struct node
{
int x,y;
int dis;
};
void dfs(int x,int y,int tx,int ty,int d)
{
if(x==tx&&y==ty)//到达终点
{
flag=1;
return ;
}
d=(d+3)%4;//改变方向
for(int i=d;i<d+4;i++)//四个方向枚举,注意顺序
{
int xx=x+dd[i%4][0];
int yy=y+dd[i%4][1];
if(xx>=0&&xx<h&&yy>=0&&yy<w&&map[xx][yy]!='#')//可以走
{
Count++;//步数加一
d=i;//更新方向
dfs(xx,yy,tx,ty,d);//继续搜索
if(flag)//已到达终点,直接返回
return ;
}
}
}
void bfs()
{
queue<node>P;
node now,temp;
now.x=sx;
now.y=sy;
now.dis=1;
P.push(now);//起点入队
while(!P.empty())
{
now=P.front();//出队
P.pop();
if(map[now.x][now.y]=='E')//到达终点
{
cout<<now.dis<<endl;
return ;
}
for(int i=0;i<4;i++)//四个方向枚举
{
temp.x=now.x+dd[i][0];
temp.y=now.y+dd[i][1];
temp.dis=now.dis+1;//步数加一
if(!vis[temp.x][temp.y]&&temp.x>=0&&temp.x<h&&temp.y>=0&&temp.y<w&&map[temp.x][temp.y]!='#')//可以走
{
vis[temp.x][temp.y]=true;//标记该点
P.push(temp);//入队
}
}
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&w,&h);
for(int i=0;i<h;i++)
{
getchar();
for(int j=0;j<w;j++)
{
scanf("%c",&map[i][j]);
if(map[i][j]=='S')//起点坐标
sx=i,sy=j;
if(map[i][j]=='E')//终点坐标
ex=i,ey=j;
}
}
flag=0;//标志变量初始化
Count=1;//步数初始化
dfs(sx,sy,ex,ey,0);//从起点到终点左转优先
cout<<Count<<" ";
flag=0;//标志变量初始化
Count=1;//步数初始化
dfs(ex,ey,sx,sy,0);//从终点到起点左转优先即为从起点到终点右转优先
cout<<Count<<" ";
memset(vis,false,sizeof(vis));//初始化标记数组
bfs();
}
return 0;
}