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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章