[CODEVS1911] 孤岛营救问题(分层图最短路)
吐槽:神tm网络流。。。
用持有的钥匙分层,状态压缩,用 2 进制表示持有的钥匙集合。
dis[i][j][k] 表示持有的钥匙集合为 k,到达点 (i, j) 的最短路径。
分层图的最短路听上去很玄乎,其实通过代码来看还是很好理解的。
——代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define N 20 6 #define min(x, y) ((x) < (y) ? (x) : (y)) 7 8 int n, m, p, ans = ~(1 << 31); 9 int map[N][N][N][N], key[N][N], dis[N][N][1 << 11]; 10 int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; 11 bool vis[N][N][1 << 11]; 12 13 struct node 14 { 15 int x, y, s; 16 node(int x = 0, int y = 0, int s = 0) : x(x), y(y), s(s) {} 17 }; 18 19 std::queue <node> q; 20 21 inline int read() 22 { 23 int x = 0, f = 1; 24 char ch = getchar(); 25 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 26 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 27 return x * f; 28 } 29 30 inline bool Acc(int x1, int y1, int x2, int y2, int s) 31 { 32 int need_key = map[x1][y1][x2][y2]; 33 if(!need_key) return 0; 34 if(need_key == -1) return 1; 35 return (s >> need_key - 1) & 1; 36 } 37 38 inline void spfa() 39 { 40 node now; 41 int i, s, x, y; 42 memset(dis, 127 / 3, sizeof(dis)); 43 dis[1][1][0] = 0; 44 q.push(node(1, 1, 0)); 45 while(!q.empty()) 46 { 47 now = q.front(); 48 q.pop(); 49 vis[now.x][now.y][now.s] = 0; 50 for(i = 0; i < 4; i++) 51 { 52 x = now.x + dx[i]; 53 y = now.y + dy[i]; 54 s = now.s | key[x][y]; 55 if(!x || x > n || !y || y > m) continue; 56 if(Acc(now.x, now.y, x, y, now.s)) 57 if(dis[x][y][s] > dis[now.x][now.y][now.s] + 1) 58 { 59 dis[x][y][s] = dis[now.x][now.y][now.s] + 1; 60 if(!vis[x][y][s]) 61 { 62 vis[x][y][s] = 1; 63 q.push(node(x, y, s)); 64 } 65 } 66 } 67 } 68 } 69 70 int main() 71 { 72 int i, j, a, b, c, d, x, y, z, doors, keys; 73 n = read(); 74 m = read(); 75 p = read(); 76 doors = read(); 77 memset(map, -1, sizeof(map)); 78 for(i = 1; i <= doors; i++) 79 { 80 a = read(); 81 b = read(); 82 c = read(); 83 d = read(); 84 map[a][b][c][d] = map[c][d][a][b] = read(); 85 } 86 keys = read(); 87 for(i = 1; i <= keys; i++) 88 { 89 x = read(); 90 y = read(); 91 z = read(); 92 key[x][y] |= 1 << z - 1; 93 } 94 spfa(); 95 for(i = 0; i < (1 << 11); i++) ans = min(ans, dis[n][m][i]); 96 if(ans == 707406378) ans = -1; 97 printf("%d\n", ans); 98 return 0; 99 }