UVa Problem 10047 The Monocycle(独轮车)

// The Monocycle(独轮车)
// PC/UVa IDs: 111202/10047, Popularity: C, Success rate: average Level: 3
// Verdict: Accepted
// Submission Date: 2011-11-01
// UVa Run Time: 0.076s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [解题方法]
// 本题可以归结为图的遍历,动态规划问题。题目所要求的是到达终点 T 时,轮子绿色部分中心着地时的最短
// 时间,如果能通过遍历到达终点 T,则肯定存在一个最短时间,否则说明起点 S 和终点 T 之间无通路,目
// 标不可达。若遍历能到达终点 T,不一定刚好是绿色部分中心着地,即走的步数刚好是 5 的倍数,那么就
// 需要从这些路径中选一条达到终点 T 时,中心着地部分为绿色且时间最短的一条,这个可以通过动态规划
// 来解决。使用 minTime[i][j][c][d] 表示在位置(i,j)颜色为 c,方向为 d 时的最小到达时间,
// 在遍历中更新该时间,大于等于该时间的同等状态不再继续扩展进行遍历,最后取终点 T,中心着地颜色为
// 绿色时的到达时间最小值,若最小值还是预设的 MAXINT,则表示目标不可达。

#include <iostream>
#include <queue>
#include <set>

using namespace std;

#define MAXN 25			// 地面大小最大值。
#define MAXCOLORS 5		// 颜色数目。
#define MAXD 4			// 方向数目。
#define MAXINT (1 << 20)	// 预设的最大时间。为该值则表示不可达。

// 面朝方向。
#define NORTH 0
#define SOUTH 1
#define WEST 2
#define EAST 3

// 中心着地部分颜色。
#define GREEN 0
#define BLACK 1
#define RED 2
#define BLUE 3
#define WHITE 4

// 独轮车手状态。
struct state
{
	int x, y;	// 所处位置。
	int time;	// 已用时间。
	int direction;	// 面朝方向。
	int color;	// 中心着地部分颜色。
};

// 到达位置(i,j)时,中心着地部分颜色为 c,方向为 d 时的最小时间。
int minTime[MAXN][MAXN][MAXCOLORS][MAXD];
// 表示地面的字符数组。
char matrix[MAXN][MAXN];
// 测试例数,表示地面矩阵的行数,列数。
int cases = 1, line, row;
// 从当前方向 i 到转到方向 j 所需时间,如 delay[NORTH][SOUTH] 表示从朝北方向转到朝南方向,所
// 需时间为 2 秒,因为要在原地转两次 90 度。
int delay[MAXD][MAXD] = {
	{ 0, 2, 1, 1 }, { 2, 0, 1, 1 }, { 1, 1, 0, 2 }, { 1, 1, 2, 0 } };
int offset[MAXD][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
// 表示起点和终点的位置。
pair < int, int > sIndex, tIndex;

void dynamic_programming(void)
{
	// 置初始值。
	for (int i = 0; i < line; i++)
		for (int j = 0; j < row; j++)
			for (int c = GREEN; c <= WHITE; c++)
				for (int d = NORTH; d <= EAST; d++)
					minTime[i][j][c][d] = MAXINT;
	
	// 压入初始状态。
	queue < state > states;
	states.push((state){sIndex.first, sIndex.second, 0, NORTH, GREEN});
	
	// 宽度优先遍历。
	while (!states.empty())
	{
		state s = states.front();
		states.pop();

		// 比较状态,更新相同状态到达时间的最小值。
		if (s.time >= minTime[s.x][s.y][s.color][s.direction])
			continue;
		else
			minTime[s.x][s.y][s.color][s.direction] = s.time;

		// 原地转方向。
		for (int d = NORTH; d <= EAST; d++)
		{
			if (d == s.direction)
				continue;

			states.push((state){s.x, s.y, s.time +
					delay[s.direction][d], d, s.color});
		}

		// 若前后左右无障碍且在地面范围内,则前进。
		for (int d = NORTH; d <= EAST; d++)
		{
			int x = s.x + offset[d][0];
			int y = s.y + offset[d][1];
			
			if (x < 0 || x >= line || y < 0 || y >= row)
				continue;
			if (matrix[x][y] == '#')
				continue;

			states.push((state){x, y, s.time + delay[s.direction][d] + 1, 
						d, (s.color + 1) % MAXCOLORS});
		}
	}

	// 取到达终点 T 时的最小到达时间。
	int minimum = MAXINT;
	for (int i = NORTH; i <= EAST; i++)
		 minimum = min(minimum, minTime[tIndex.first][tIndex.second][GREEN][i]);

	// 输出空行。
	if (cases >= 2)
		cout << endl;

	// 输出结果。
	cout << "Case #" << cases++ << endl;
	if (minimum < MAXINT)
		cout << "minimum time = " << minimum << " sec" << endl;
	else
		cout << "destination not reachable" << endl;
}

int main(int ac, char *av[])
{
	while (cin >> line >> row, line || row)
	{
		for (int i = 0; i < line; i++)
			for (int j = 0; j < row; j++)
			{
				cin >> matrix[i][j];
				if (matrix[i][j] == 'S')
					sIndex = make_pair(i, j);
				if (matrix[i][j] == 'T')
					tIndex = make_pair(i, j);
			}

		dynamic_programming();
	}

	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值