您的位置:首页 > 其它

UVa Problem 10047 The Monocycle(独轮车)

2011-11-01 21:00 393 查看
// 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: