acdream 1242 Driving Straight bfs

传送门: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;
}


发布了109 篇原创文章 · 获赞 5 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章