luogu4011 孤岛营救问题 分层图
关键词:分层图 状态压缩 最短路径
分层图:现在要求从起点到终点的最优路线,但受到手里拿着哪些钥匙的影响,最优路线不单纯了。因此,决定一个节点、一条边的存在的数中应当增加一个手中拿有钥匙的状态。这样就相当于把一张图按拿有钥匙的状态数分出了很多层。
状态压缩:手中拿有钥匙的状态可以压缩到一个整数中。
最短路径:手中拿有钥匙的状态固定了,在分层图中我们就不再用得着走回头路了。这样就转化成了最短路径问题。
#include <cstdio> #include <cassert> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAX_X = 20, MAX_Y = 20, MAX_KEY = 20, MAX_S = 1 << 11, INF = 0x3f3f3f3f; int Dist[MAX_X][MAX_Y][MAX_S]; int Key[MAX_X][MAX_Y]; int Gate[MAX_X][MAX_Y][MAX_X][MAX_Y]; int TotX, TotY; const int xNext[] = { 0,-1,0,0,1 }, yNext[] = { 0, 0,1,-1,0 }; struct Queue { int xs[MAX_X*MAX_Y*MAX_S], ys[MAX_X*MAX_Y*MAX_S], ss[MAX_X*MAX_Y*MAX_S]; int head, tail; Queue() { head = tail = 0; } void push(int x, int y, int s) { xs[tail] = x; ys[tail] = y; ss[tail] = s; tail++; } void pop() { head++; } bool empty() { return head == tail; } int frontX() { return xs[head]; } int frontY() { return ys[head]; } int frontS() { return ss[head]; } }; int Bfs() { int ans = INF; static Queue q; Dist[1][1][Key[1][1]] = 0; q.push(1, 1, Key[1][1]); while (!q.empty()) { int x = q.frontX(), y = q.frontY(), s = q.frontS(); q.pop(); Dist[x][y][s | Key[x][y]] = Dist[x][y][s]; s |= Key[x][y]; for (int p = 1; p <= 4; p++) { int x2 = x + xNext[p], y2 = y + yNext[p]; if (x2 >= 1 && x2 <= TotX && y2 >= 1 && y2 <= TotY && Dist[x2][y2][s]==INF && (Gate[x][y][x2][y2] == -1 || s&(1 << Gate[x][y][x2][y2]))) { Dist[x2][y2][s] = Dist[x][y][s] + 1; q.push(x2, y2, s); if (x2 == TotX&&y2 == TotY) ans = min(ans, Dist[x2][y2][s]); } } } return ans; } int main() { #ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin); #endif int totObs, totKeySort, x1, x2, y1, y2, gate, totKey, key; memset(Gate, -1, sizeof(Gate)); memset(Dist, INF, sizeof(Dist)); scanf("%d%d%d%d", &TotX, &TotY, &totKeySort, &totObs); while (totObs--) { scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &gate); Gate[x1][y1][x2][y2] = Gate[x2][y2][x1][y1] = gate; } scanf("%d", &totKey); while (totKey--) { scanf("%d%d%d", &x1, &y1, &key); if (key >= 32) printf("error\n"); Key[x1][y1] |= 1 << key; } int ans = Bfs(); if (ans == INF) printf("-1\n"); else printf("%d\n", ans); return 0; }