孤岛营救

思路:

因为 \(G_i \leq 10\) ,所以我们需要二进制压缩一下获得的钥匙种类

\(d[pos][s]\) 表示从 \((1,1)\) 走到 \(pos\) ,获得的钥匙状态是 \(s\) 的所有路线中的最短距离

考虑状态:

如果一个点中没有钥匙,即为 \(d[pos][0]\)

如果一个点中没有钥匙,可以选择取或者不取,即为 \(d[pos][c]\) 或者 \(d[pos][0]\)

考虑转移方程:

拿起钥匙(不需要时间): \(d[pos][s] = min(d[pos][s], d[pos][0])\)

向四周移动(花费1 \(s\)) : \(d[pos][s] = min(d[pos][s], d[pos2][s] + 1)\)

因为 \(dp\) 实际上可以看做拓扑图上的最短路问题,因此可以将其看成边权为0/1的最短路,考虑用双端 \(bfs\) 解决(或者 \(dij, spfa\) 都可)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 11, M = 360, P = 1 << 10;
int n, m, k, p;
int head[N * N], ver[M], ne[M], egde[M], tot;
int g[N][N], key[N * N];
int d[N * N][P];
bool v[N * N][P];
int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};
set<PII>e;
void add(int x, int y, int z) {
	ver[++tot] = y, egde[tot] = z, ne[tot] = head[x], head[x] = tot;
} 
void build () {
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			for (int k = 0; k < 4; k++) {
				int x = i + dx[k], y = j + dy[k];
				if (x < 1 || x > n || y < 1 || y > m) continue;
				int a = g[i][j], b = g[x][y];
				if (!e.count(make_pair(a, b))) add(a, b, 0);
			}
		}
	}
}
int bfs () {
	memset(d, 0x3f, sizeof d);
	d[1][0] = 0;
	deque<PII> q;
	q.push_back(make_pair(1, 0));
	while (q.size()) {
		PII t = q.front();
		q.pop_front();
		int pos = t.first, s1 = t.second;
		if (v[pos][s1]) continue;
		v[pos][s1] = 1;
		if (pos == n * m) return d[pos][s1];
		if (key[pos]) {
			int s2 = s1 | key[pos];
			if (d[pos][s2] > d[pos][s1]) {
				d[pos][s2] = d[pos][s1];
				q.push_front(make_pair(pos, s2));
			}
		}
		for (int i = head[pos]; i; i = ne[i]) {
			int y = ver[i], z = egde[i];
			if (!v[y][s1]) {
				if (z && !(s1 >> (z - 1) & 1)) continue;
				if (d[y][s1] > d[pos][s1] + 1) {
					d[y][s1] = d[pos][s1] + 1;
					q.push_back(make_pair(y, s1));
				}
			}
		}
	}
	return -1;
}
int main () {
	cin >> n >> m >> p >> k;
	for (int i = 1, t = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++, t++) g[i][j] = t;
	}
	memset(head, -1, sizeof head);
	while (k--) {
		int x1, y1, x2, y2, c;
		cin >> x1 >> y1 >> x2 >> y2 >> c;
		int a = g[x1][y1], b = g[x2][y2];
		e.insert(make_pair(a, b)), e.insert(make_pair(b, a));
		if (c) add(a, b, c), add(b, a, c);
	}
	build ();
	int s;
	cin >> s;
	while (s--) {
		int x, y, c;
		cin >> x >> y >> c;
		key[g[x][y]] |= 1 << c - 1;
	}
	cout << bfs() << endl;
	return 0;
}
posted @ 2022-08-11 09:43  misasteria  阅读(33)  评论(0编辑  收藏  举报