傳送門: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;
}