UVa 10047 - The Monocycle

传送门UVa 10047 - The Monocycle


走迷宫的一道题,和以往不同的是这次走过的地方可以走,除非状态(颜色,方向)和上一次完全相同。

所以要开一个四维数组,记录这两个状态。

题目要求用时最短,这时就需要一个优先队列。每次从队列中取元素时,总是取的用时最短的那个。所以最后满足终点条件的时候输出的就是时间最短的。


因为优先队列默认从大到小排序,所以要重载<运算符(我是这么理解的),不过应该也可以写一个比较函数,改变默认排序顺序。


还是参考了@shuangde800的解题报告,加了点注释,方便大家理解。


至此,除了最后一题,图专题结束。最后一题就等暑假结束再来吧。。。


#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;


struct Node
{
	int dir, color, time;
	int x, y;
	friend bool operator < (const Node &a, const Node &b)
	{
		return a.time > b.time;
	}
};

const int MAXN = 30;
char maze[MAXN][MAXN];
int vis[MAXN][MAXN][4][5];   // 绿0,白1,黑2,红3,蓝4  
int dir[][2] = {{-1,0},{0,1},{1,0},{0,-1}}; // 上0,右1,下2,左3,这里要和i对应,不然会错。
int xStart, yStart, xTarget, yTarget;	//起点和终点的坐标
int row, colomn;
Node start, temp, stemp;	
priority_queue<Node> que;

void BFS();

int main()
{
	//freopen("input.txt", "r", stdin);
	int i, j, n;
	bool sFind, tFind;
	int cnt = 1;
	while (scanf("%d%d%*c", &row, &colomn))
	{
		memset(vis, 0, sizeof(vis));
		memset(maze, 0, sizeof(maze));
		sFind = tFind = false;
		if (row + colomn == 0)
			break;
		for (i = 0; i < row; i++)
			scanf("%s%*c", maze[i]);
		for (i = 0; i < row; i++)
		{
			for (j = 0; j < strlen(maze[i]); j++)
			{
				if (sFind && tFind)	//如果起始坐标和终点坐标都找到,退出。
					break;
				if (maze[i][j] == 'S')
				{
					xStart = i, yStart = j;
					sFind = true;
				}
				if (maze[i][j] == 'T')
				{
					xTarget = i, yTarget = j;
					tFind = true;
				}
			}
		}
		start.x = xStart, start.y = yStart, start.color = start.dir = start.time = 0;
		if (cnt != 1)
			printf("\n");
		printf("Case #%d\n", cnt++);
		BFS();
	}
	return 0;
}

void BFS()
{
	while (!que.empty())	//清空队列。
		que.pop();
	vis[start.x][start.y][start.dir][start.color] = 1;
	que.push(start);
	while (!que.empty())
	{
		temp = que.top();
		que.pop();
		for (int i = 0; i < 4; i++)		//按顺序分别对应。上0,右1,下2,左3
		{
			int dx = temp.x + dir[i][0];
			int dy = temp.y + dir[i][1];
			if (dx >= 0 && dy >= 0 && dx < row && dy < colomn && maze[dx][dy] != '#')
			{
				if (temp.dir == i)	//如果要走的方向和当前方向相同,直接走,变颜色,不变方向。
				{
					stemp.time = temp.time + 1;
					stemp.color = (temp.color + 1) % 5;
					stemp.dir = i;
					stemp.x = dx, stemp.y = dy;
				}
				else	//如果方向和车头不一致,原地转弯
				{
					if (abs(temp.dir - i) == 2)		//相差180°,时间+2,坐标都不变
						stemp.time = temp.time + 2;
					else
						stemp.time = temp.time + 1;
					stemp.dir = i;
					stemp.color = temp.color;
					stemp.x = temp.x, stemp.y = temp.y;
				}
				if (!vis[stemp.x][stemp.y][i][stemp.color])
				{
					if (stemp.x == xTarget && stemp.y == yTarget && stemp.color == 0)
					{
						printf("minimum time = %d sec\n", stemp.time);
						return;
					}
					que.push(stemp);
					vis[stemp.x][stemp.y][i][stemp.color] = 1;
				}
			}
		}
		
	}
	printf("destination not reachable\n");
}



你可能感兴趣的:(ACM,uva)