传送门:acdream 1242
给定一张图,求出从左下角走到右上角的最短路,并输出走法
bfs求最短路,因为给出的图用'-','|'分别表示横向与纵向连通,因此可以预处理整张图,判断每个点的4个方向是否可走,然后bfs记录下以dir方向第一次到达x,y点时的行为。再从终点回溯,即可求出整条路径上的行为
处理的东西比较多,需要耐心,最好在写代码的同时就加上注释,不然写到一半自己都糊涂了
/******************************************************
* File Name: h.cpp
* Author: kojimai
* Creater Time:2014年10月07日 星期二 13时41分31秒
******************************************************/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define FFF 405
bool map[FFF][FFF][4];//判定每个点4个方向上是否连通
char s[FFF*2][FFF*2];//读取题目给的图
int n,m,vis[FFF][FFF][4],move[4][2]={ -1,0,0,1,1,0,0,-1 };//0-up 1-right 2-down 3-left
void init()
{
for(int i = 0;i < n;i++)
{
for(int j = 1;j < m;j++)
{
//cout<<"x y = "<<i*2<<' '<<j*2-1<<" s = "<<s[i*2][j*2-1]<<endl;
if(s[i*2][j*2-1] == '-')//横向上是否连通
{
map[i][j-1][1] = true;
map[i][j][3] = true;
}
}
}
for(int i = 1;i < n;i++)
{
for(int j = 0;j < m;j++)
{
//cout<<"x y = "<<i*2-1<<' '<<j*2<<" s = "<<s[i*2-1][j*2]<<endl;
if(s[i*2-1][j*2] == '|')//纵向上是否连通
{
map[i-1][j][2] = true;
map[i][j][0] = true;
}
}
}
return;
}
struct node
{
int x,y,t,dir;
};
queue<node> p;
int bfs()
{
node now,tmp;
now.x=n-1;now.y=0;now.t=0;now.dir=0;
vis[n-1][0][0] = 2;
p.push(now);
now.dir = 1;
vis[n-1][0][0] = 3;
p.push(now);
while(!p.empty())
{
now = p.front();p.pop();
// cout<<"now.x = "<<now.x<<" now.y = "<<now.y<<" now.dir = "<<now.dir<<endl;
if(now.x == 0&&now.y == m-1)
return now.dir;//到达终点时,记录到达终点时面朝的方向,以回溯找路径
tmp.t = now.t + 1;
//cout<<" map="<<map[now.x][now.y][now.dir]<<endl;
if(map[now.x][now.y][now.dir])//判断当前点的当前方向是否可走
{
tmp.x = now.x + move[now.dir][0];
tmp.y = now.y + move[now.dir][1];
tmp.dir = now.dir;
if(vis[tmp.x][tmp.y][tmp.dir] == -1)//这个点以这个方向还没有到达过
{
vis[tmp.x][tmp.y][tmp.dir] = 0;//记录到达该点的行为方式——直走
p.push(tmp);
}
}
tmp.dir = (now.dir + 1)%4;//右转之后的方向
if(map[now.x][now.y][tmp.dir])
{
tmp.x = now.x + move[tmp.dir][0];
tmp.y = now.y + move[tmp.dir][1];
if(vis[tmp.x][tmp.y][tmp.dir] == -1)
{
vis[tmp.x][tmp.y][tmp.dir] = 1;//记录到达该点的行为——右转
p.push(tmp);
}
}
tmp.dir = (now.dir + 3)%4;
if(map[now.x][now.y][tmp.dir])
{
tmp.x = now.x + move[tmp.dir][0];
tmp.y = now.y + move[tmp.dir][1];
if(vis[tmp.x][tmp.y][tmp.dir] == -1)
{
vis[tmp.x][tmp.y][tmp.dir] = 2;//记录到达该点的行为——左转
p.push(tmp);
}
}
}
}
int ans[160005];
int main()
{
scanf("%d%d",&n,&m);
getchar();
for(int i = 0;i < n*2-1;i++)
gets(s[i]);
//for(int i =0;i< n*2;i++)
// cout<<s[i]<<endl;
memset(map,false,sizeof(map));
init();
//cout<<"fuckinit()"<<endl;
memset(vis,-1,sizeof(vis));
memset(road,-1,sizeof(road));
int dd=bfs();
//cout<<"dd="<<dd<<endl;
int cnt = 0,x = 0,y = m-1;
while(1)
{
//cout<<" x = "<<x<<" y = "<<y<<" dd = "<<dd<<" vis="<<vis[x][y][dd]<<endl;
ans[cnt] = vis[x][y][dd];
int dir = (dd+2)%4;//走面朝向的反方向即可回溯路径
int xx = x + move[dir][0];
int yy = y + move[dir][1];
if(xx==n-1&&yy==0)//回溯到了起点直接退出,依据当前点的方向判断起点时面朝的方向
break;
if(ans[cnt]==0)//直走时,不调整前一个点的方向
dd = dd;
else if(ans[cnt] == 1)//右转到达当前点
{
dd = (dd+3)%4;//回溯到前一个点时左转
}
else
dd = (dd+1)%4;//左转到达当前点,右转回溯
x = xx;y = yy;
cnt++;
}
if(dd==0)
printf("N\n");
else
printf("E\n");
for(int i = cnt-1;i>=0;i--)
{
if(ans[i]==0)
printf("F");
else if(ans[i]==1)
printf("R");
else
printf("L");
}
cout<<endl;
return 0;
}