(advanced) UVA 最短路 10381 - The Rock

Problem D
The Rock
Input:
standard input
Output: standard output
Time Limit: 12 seconds
Memory Limit: 32 MB

 

A group of terrorists have taken hostages on the former prison island Alcatraz (now a tourist attraction) outside San Francisco, and is demanding a big ransom from the US government. If they are not paid within 40 hours, they will launch 15 rockets of V.X. poison gas at San Francisco, each rocket capable of killing 70,000 people.

The Pentagon is planning on sending a SEAL team to Alcatraz to destroy the rockets. They intend to penetrate the island through the tunnels under the prison building, but because the prison has been rebuilt so many times, all the maps of the tunnels are useless. The only man who can help them is John Mason, a former inmate who once successfully escaped from Alcatraz through the tunnels.

However, Mason is getting old so he doesn't remember all the details of the tunnels. More precisely, he knows that there is exactly one wall whose location he doesn't remember. Since they're running out of time, they want to make sure that they take a path which will guarantee the shortest possible time to reach the exit of the tunnels no matter where this extra wall is. Since you're the top program writer at the Pentagon, it's your job to write the program to find this shortest path!

For simplicity, we can assume that the tunnels below Alcatraz can be described as a rectangular grid, where each grid square is either wall or open space, and walking is permitted only between adjacent non-wall squares. Two squares are adjacent if they have one side in common. The additional, unknown, wall occupies exactly one square, and the team will not notice this wall until they've reached an adjacent square to it.

Example:

 
..X.....
........
##.##...
........
##.##...
##.##...
........
..E.....

If the team walks straight ahead from the entrance (E), they may face a wall at row 4 column 3, in which case they have to turn around and the length of the path will be 17. It's better to walk to the right immediately, as this will ensure a path of length at most 15.

Input

The first line in the input will contain one integer n (n ≤ 10) which is the number of maps to process. Then follows the n map descriptions.

Each map description starts with a blank line, followed by a line with two integers, describing the number of rows and columns in the map, respectively. The map then follows one row on each line. '#' is used for walls, '.' for open space, 'E' is the entrance and 'X' is the exit. The number of rows and columns in the map is at least 3 and at most 40.

You may assume that the map is valid and that there will be exactly one entrance and one exit square. You may also assume that there exist at least two disjoint paths (sharing no squares except the entrance and exit) from the entrance to the exit and that the additional wall will neither be on the entrance nor exit square.

Output

For each map, output a single line containing the length of the shortest path according to the description above.

 

Sample Input

2
 
8 8
..X.....
........
##.##...
........
##.##...
##.##...
........
..E.....
 
3 4
..X.
.##.
.E..

 

Sample Output

15
11

(Regionals 2002 Warm-up Contest, Problem setter: Jimmy Mårdell) 


题意:有一个迷宫,有一个入口和出口,其中有一道隐形的墙,你不知道他在哪里,你需要设计一种行走路线,使得最坏的情况下路径最短。


思路:首先我们来分析一下这道“隐形”的墙怎么让你的情况最差。首先我们任意选择一条路线。那么这道墙可能出现这个路线上的任意一点,如果出现了,我们不得不绕路走,当然绕路后也要走最短的。这时候我们另外一个路径。把每个点逐个当做是隐形的墙得出的各个路径中最长的,就是这条路径的最差情况。根据这些,我们得知,当我们在走的时候,我们要不断的计算如果出现墙后的路径是多少,我们要取这些所有路径最大的。所以我们设计出状态(r,c,g,h)分别表示的是所处的行、列、步数、目前“绕路走”中最常的长度。用这个状态进行搜索就行。我们每次只需要取所有状态中h最小的。还要用一个done[r][c][g]记录从起点到达(r,c)步数为g时,最小的h值。“绕路走”的长度,我们预处理一下在(r,c)往dir方向跑碰到隐形墙而绕到终点的距离。那么搜的时候可以直接得出h值。有了这些思路,基本就能做出来了。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<queue>
using namespace std;
#define mp make_pair
const int maxn = 40 + 2;
const int inf = 1e8;
int n, m;
const int Move[2][4] = { { -1, 0, 1, 0 }, { 0, 1, 0, -1 } };
inline int row(int x) { return x / m; }
inline int col(int x) { return x%m; }
inline int getx(int r, int c) { return r*m + c; }
inline bool inRange(int r, int c) { return 0 <= r&&r < n && 0 <= c&&c < m; }
char maze[maxn][maxn];
int d[maxn*maxn];
int done[maxn*maxn][maxn*maxn];
int w[maxn*maxn][4];
int s, t;

void bfs()
{
	queue<int> q;
	q.push(t);
	memset(d, 0x3f, sizeof(d));
	d[t] = 0;
	while (q.size())
	{
		int x = q.front(); q.pop();
		int r = row(x), c = col(x);
		for (int i = 0; i < 4; ++i)
		{
			int rr = r + Move[0][i];
			int cc = c + Move[1][i];
			if (!inRange(rr, cc) || maze[rr][cc] == '#') continue;
			int y = getx(rr, cc);
			if (d[y] <= d[x] + 1) continue;
			d[y] = d[x] + 1;
			q.push(y);
		}
	}
}

void input()
{
	for (int i = 0; i < n; ++i)
	{
		scanf("%s", maze[i]);
		for (int j = 0; j < m; ++j)
		{
			if (maze[i][j] == 'E') s = getx(i, j);
			else if (maze[i][j] == 'X') t = getx(i, j);
		}
	}
	memset(w, 0, sizeof(w));
	for (int r = 0; r < n;++r)
	for (int c = 0; c < m; ++c)
	{
		if (maze[r][c] != '.') continue;
		maze[r][c] = '#';
		bfs();
		for (int k = 0; k < 4; ++k)
		{
			int rr = r + Move[0][k];
			int cc = c + Move[1][k];
			if (!inRange(rr, cc) || maze[rr][cc] == '#') continue;
			int y = getx(rr, cc);
			w[y][(k+2)%4] = d[y];
		}
		maze[r][c] = '.';
	}
}

struct State
{
	int g;
	int h;
	int x;
	bool operator<(const State&st) const { return h>st.h; }
};

int Dijkstra()
{
	priority_queue<State> q;
	memset(done, 0x3f, sizeof(done));
	State S;
	S.g = 0; S.h = 0;
	S.x = s;
	q.push(S);
	while (q.size())
	{
		State temp = q.top(); q.pop();
		int x = temp.x, g = temp.g;
		if (done[x][g] <= temp.h) continue;
		if (x == t) return temp.h;
		done[x][g] = temp.h;
		int r = row(x), c = col(x);
		for (int i = 0; i < 4; ++i)
		{
			int rr = r + Move[0][i];
			int cc = c + Move[1][i];
			if (!inRange(rr, cc) || maze[rr][cc] == '#') continue;
			if (maze[rr][cc] == 'E') continue;
			int y = getx(rr, cc);
			State now = temp;
			++now.g;
			if (maze[rr][cc] == '.') now.h = max(now.h, g + w[x][i]);
			else if (maze[rr][cc]=='X') now.h = max(now.h, now.g);
			now.x = y;
			q.push(now);
		}
	}
	return -1;
}

void solve()
{
	int ans = Dijkstra();
	printf("%d\n", ans);
}


int main()
{
	//freopen("input.in", "r", stdin);
	int T; cin >> T;
	while (T--)
	{
		scanf("%d%d", &n, &m);
		input();
		solve();
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值