【“盛大遊戲杯”第15屆上海大學程序設計聯賽 O】【爆搜 最短路】隨機傳送 需要補題解

隨機傳送迷宮

發佈時間: 2017年7月9日 18:17   最後更新: 2017年7月9日 21:04   時間限制: 1000ms   內存限制: 128M

小Y做了一個隨機迷宮生成器,生成的迷宮可以用nm的矩陣來表示,人物可以從迷宮的起點開始,每個單位時間選擇往上下左右走一步,但不能走到不能通行的格子或者走出矩陣外。在迷宮中會有不定數量的傳送門,其中傳送門入口與傳送門出口一一對應,如果人物處在傳送門入口處,可以用一個單位的時間使用這個傳送門入口到達一個傳送門出口處,但是在嘗試之前你並不知道哪一個傳送門入口對應哪一個出口,因此小Y想知道用什麼樣的策略走才能在最壞情況下花費最少時間到達迷宮的出口。傳送門只能單向通行,但是可以重複使用,由於傳送門入口出口一一對應,因此重複使用傳送門會到達同一個傳送門出口。

第一行有一個整數T表示數據組數。(T<=50
接着有T組數據,每組數據第一行有兩個整數nm。(2<=n,m<=100
接着有n行,m列的迷宮矩陣。
其中字符'S','T'分別表示唯一的迷宮起點和終點,
字符'#'表示無法通行的障礙,
字符'.'表示空地,
字符'i','o'分別表示傳送門入口和出口。(傳送門入口與出口數量相同,並且數量都不超過5)

對於每組數據輸出一行,表示花費的最少單位時間,如果不存在一定能走到出口的方案,則輸出-1。

3
4 4
Siii
..oo
####
T..o
4 4
S..i
i###
#.#o
T.o#
5 4
o.Si
###i
.oo#
i###
i#oT
9
-1
16

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m, g;
char s[N][N];
struct Point
{
	int y, x;
}ST, ED;

//用於求出狀態,得到ID->確定狀態的映射match,和確定狀態->ID的映射mop
vector<int> VT;
vector<int> match[2000]; int matchID;
map<vector<int>, int> mop;
bool vis[10];
void dfs(int p)
{
	if (p == g)
	{
		match[matchID] = VT;
		mop[VT] = matchID++;
		return;
	}
	VT[p] = g;
	dfs(p + 1);
	for (int i = 0; i < g; ++i)if (!vis[i])
	{
		vis[i] = 1;
		VT[p] = i;
		dfs(p + 1);
		vis[i] = 0;
	}
}

//用於求出特殊點之間的距離
Point I[10], O[10];
int in[N][N], out[N][N];
const int dy[4] = { -1, 0, 0, 1 };
const int dx[4] = { 0, -1, 1, 0 };
int DIS[6][6];
int d[N][N];
void bfs(int o)
{
	MS(d, 63); d[O[o].y][O[o].x] = 0;
	queue<Point>q; q.push(O[o]);
	while (!q.empty())
	{
		Point now = q.front(); q.pop();
		int step = d[now.y][now.x] + 1;
		for (int k = 0; k < 4; ++k)
		{
			int yy = now.y + dy[k];
			int xx = now.x + dx[k];
			if (s[yy][xx] == '#')continue;
			if (step < d[yy][xx])
			{
				d[yy][xx] = step;
				q.push({ yy,xx });
				if (in[yy][xx] <= g)
				{
					DIS[o][in[yy][xx]] = step;
				}
			}
		}
	}
}

//狀態由兩部分構成,當前的狀態,最後的位置
int f[2000][6];
int canIN[6];
int canOUT[6];
bool sureOUT[6];
int dfs(int ID, int p)
{
	if (f[ID][p] != inf)return f[ID][p];
	int canINnum = 0, canOUTnum = 0;
	MS(sureOUT, 0);
	for (int i = 0; i < g; ++i)
	{
		if (match[ID][i] == g)
			canIN[canINnum++] = i;
		else
			sureOUT[match[ID][i]] = 1;
	}
	for (int i = 0; i < g; ++i)
		if (!sureOUT[i])
			canOUT[canOUTnum++] = i;

	//枚舉入口
	f[ID][p] = DIS[p][g];
	for (int i = 0; i < canINnum; ++i)
	{
		int gohere = 0;
		int x = canIN[i];
		//枚舉出口
		for (int j = 0; j < canOUTnum; ++j)
		{
			int y = canOUT[j];
			if (DIS[p][x] == inf)
			{
				gohere = inf;
				break;
			}
			vector<int>vt = match[ID];
			vt[x] = y;
			int nxtID = mop[vt];
			gmax(gohere, DIS[p][x] + 1 + dfs(nxtID, y));
		}
		gmin(f[ID][p], gohere);
	}
	return f[ID][p];
}

int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		scanf("%d%d", &n, &m);
		for (int i = 0; i <= n + 1; ++i)
		{
			for (int j = 0; j <= m + 1; ++j)
			{
				s[i][j] = '#';
				in[i][j] = out[i][j] = inf;
			}
		}
		int ig = 0, og = 0;
		for (int i = 1; i <= n; ++i)
		{
			scanf("%s", s[i] + 1); s[i][m + 1] = '#';
			for (int j = 1; j <= m; ++j)
			{
				if (s[i][j] == 'S')
				{
					ST = { i,j };
				}
				else if (s[i][j] == 'T')
				{
					ED = { i,j };
				}
				else if (s[i][j] == 'i')
				{
					in[i][j] = ig;
					I[ig++] = { i,j };
				}
				else if (s[i][j] == 'o')
				{
					out[i][j] = ig;
					O[og++] = { i,j };
				}
			}
		}
		g = ig; O[g] = ST; I[g] = ED; in[ED.y][ED.x] = g;
		MS(DIS, 63);
		for (int i = 0; i <= g; ++i)
			bfs(i);

		mop.clear();
		VT.resize(g);
		matchID = 0;
		dfs(0);
		MS(f, 63);
		int ans = dfs(0, g);
		if (ans >= inf)ans = -1;
		printf("%d\n", ans);
	}
	return 0;
}
/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章