UVA - 10047 The Monocycle(bfs)

UVA - 10047 The Monocycle(bfs)

A monocycle is a cycle that runs on one wheel and the one we will be considering is a bit more special.
It has a solid wheel colored with five different colors as shown in the figure:
在这里插入图片描述
The colored segments make equal angles (72o) at the center. A monocyclist rides this cycle on an M × N grid of square tiles. The tiles have such size that moving forward from the center of one tile o that of the next one makes the wheel rotate exactly 72 o around its own center. The effect is shown in the above figure. When the wheel is at the center of square 1, the midpoint of the periphery of its blue segment is in touch with the ground. But when the wheel moves forward to the center of the next
square (square 2) the midpoint of its white segment touches the ground.
在这里插入图片描述
Some of the squares of the grid are blocked and hence the cyclist cannot move to them. The cyclist tarts from some square and tries to move to a target square in minimum amount of time. From any square either he moves forward to the next square or he remains in the same square but turns 90o left or right. Each of these actions requires exactly 1 second to execute. He always starts his ride facing
north and with the midpoint of the green segment of his wheel touching the ground. In the target
square, too, the green segment must be touching the ground but he does not care about the direction
he will be facing.
Before he starts his ride, please help him find out whether the destination is reachable and if so the
minimum amount of time he will require to reach it.
Input
The input may contain multiple test cases.
The first line of each test case contains two integers M and N (1 ≤ M, N ≤ 25) giving the
dimensions of the grid. Then follows the description of the grid in M lines of N characters each. The
character ‘#’ will indicate a blocked square, all other squares are free. The starting location of the
cyclist is marked by ‘S’ and the target is marked by ‘T’.
The input terminates with two zeros for M and N.
Output
For each test case in the input first print the test case number on a separate line as shown in the
sample output. If the target location can be reached by the cyclist print the minimum amount of time
(in seconds) required to reach it exactly in the format shown in the sample output, otherwise, print
“destination not reachable”.
Print a blank line between two successive test cases.
Sample Input
1 3
S#T
10 10
#S…#
#…#.##.##
#.##.##.##
.#…##.#
##.##…#.#
#…#.##…
#…##.
…##.##…
#.###…#.
#…###T
0 0
Sample Output
Case #1
destination not reachable
Case #2
minimum time = 49 sec

题目大意:

有个车轮子,车轱辘分成了五部分,每一个部分有个颜色,每走一步,换个颜色; 车还有个方向,每一秒只能往前走,或者转向,就比如现在车面朝右吧,你只能向右走,如果你想往上走,对不起,请先花一秒时间调个头(事事子超多)。地图上还有些障碍物不能走,问,能不能从起点走到终点,还得轮子颜色是最初得颜色,最短时间多少秒。

解题思路:

求从起点到终点得时间,我们很容易想用BFS。
但是这个题又不像普通得走地图一样,它轮子毛病特别多,要求特别多,同一个点,我们有可能走两次(比如我们走到终点了,但是轮子颜色不对,我们得再溜达几步,让轮子颜色便变成合适得),所以每一步得状态要有四部分组成------当前点得坐标x和y,当前轮子得朝向,当前轮子得颜色

  • 我们用四维得标记数组来标记当前状态,保证每个状态只出现一次进行bfs。
int vis[maxx][maxx][4][5];//前两维是坐标 第三维是当前方向,第四维是颜色
  • bfs每个点得状态我们用一个结构题来表示
  • 因为我们要求最短的时间状态,所以我们要用优先队列,按时间排序,先选最小的,所以我们就要对结构体得小于号<进行重载
struct node
{

	int x;
	int y;
	int color;//颜色
	int dir;//方向
	int time;//用时
	friend bool operator < (const node& a,const node& b )
	{
		return a.time>b.time;
	}
};
  • 进行每一步时肯定得看看要走得地方是否越界?是否时墙?这样肯定就得continue;
  • 然后得判断方向,如果方向跟当前要走得方向一样,这最好,直接走,time+1,方向不变,颜色加一
if(tmp.dir==i)//同方向的
				{
					t.time=tmp.time+1;
					t.dir=i;
					t.color=(tmp.color+1)%5;
					t.x=dx;
					t.y=dy;
				}
  • 如果不同向呢?我们得先转向啊,转向得时间取决于原先方向跟当前得差多少,如果差180°那得转两次呀,就time+2,如果差90°只要让time+1即可
if(abs(tmp.dir-i)==2)//正好相反方向
						t.time=tmp.time+2;
					else
						t.time=tmp.time+1;
  • 然后再判断一下,这个状态是否之前出现过,如果没出现过,就加到优先队列里面去,如果到了终点,那就输出时间return 就行了
if(!vis[t.x][t.y][i][t.color])//之前没有过这个状态
{
if(t.x==ex&&t.y==ey&&t.color==0)//到终点了
{
	cout<<"minimum time = "<<t.time<<" sec"<<endl;
	return ;
}

q.push(t);	
vis[t.x][t.y][i][t.color]=1;
}
  • 如果队列q为空了都没到终点,那就是凉了呀,根本到不了终点啦,就直接输出"destination not reachable"就好了。

注意开始得时候别忘了把第一个结点加到设计好。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
const int maxx=100;
int n,m;
int sx,sy,ex,ey;
char mp[maxx][maxx];
int vis[maxx][maxx][4][5];//前两维是坐标 第三维是当前方向,第四维是颜色
struct node
{

	int x;
	int y;
	int color;//颜色
	int dir;//方向
	int time;//用时
	friend bool operator < (const node& a,const node& b )
	{
		return a.time>b.time;
	}
};

priority_queue <node >q;//按时间的从小到大的优先队列 保证而每次找到的都是最优的
void bfs(node ss)
{
	struct node tmp,t;
	int next[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
	while(q.size())//清空队列
		q.pop();
	q.push(ss);
	vis[ss.x][ss.y][ss.dir][ss.color]=1;
	while(!q.empty())
	{
		tmp=q.top();
		q.pop();
		for(int i=0;i<4;i++)//往周围四个方向走
		{
			int dx=tmp.x+next[i][0];
			int dy=tmp.y+next[i][1];

			if(dx>=0&&dx<n&&dy>=0&&dy<m&&mp[dx][dy]!='#')//下一个位置是合法的位置
			{
				if(tmp.dir==i)//同方向的
				{
					t.time=tmp.time+1;
					t.dir=i;
					t.color=(tmp.color+1)%5;
					t.x=dx;
					t.y=dy;
				}
				else
				{
					if(abs(tmp.dir-i)==2)//正好相反方向
						t.time=tmp.time+2;
					else
						t.time=tmp.time+1;
					t.color=tmp.color;//只是转个向但是并不动所以颜色不变
					t.dir=i;//转完之后方向就是i了
					t.x=tmp.x;
					t.y=tmp.y;
				}
				if(!vis[t.x][t.y][i][t.color])//之前没有过这个状态
				{
					if(t.x==ex&&t.y==ey&&t.color==0)//到终点了
					{
						cout<<"minimum time = "<<t.time<<" sec"<<endl;
						return ;
					}
				
					q.push(t);	
					vis[t.x][t.y][i][t.color]=1;
				}
				
			}
		}

	}
	cout<<"destination not reachable"<<endl;
}
void init()
{
	memset(vis,0,sizeof(vis));
}

int main()
{
	int cas=1;
	while(~scanf("%d%d",&n,&m))
	{
		struct node begin;
		if(n==0&&m==0)
			break;
		init();
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				cin>>mp[i][j];
				if(mp[i][j]=='S')
					sx=i,sy=j;
				else if(mp[i][j]=='T')
					ex=i,ey=j;
			}

		}
// cout<<sx<<" "<<sy<<endl;
// cout<<ex<<" "<<ey<<endl;
		begin.x=sx;
		begin.y=sy;
		begin.color=0;
		begin.dir=0;
		begin.time=0;
		if(cas!=1)
			cout<<endl;
		cout<<"Case #"<<cas++<<endl;
		bfs(begin);
	}
	return 0;
}