洛谷 P4011 孤岛营救问题【最短路+分层图】
题外话:昨夜脑子昏沉,今早一调试就过了...错误有:我忘记还有墙直接穿墙过...memset初始化INF用错了数...然后手残敲错一个状态一直过不了样例...要是这状态去比赛我简直完了......orz
题目链接:https://www.luogu.org/problemnew/show/P4011
输入输出样例
输入样例#1:
4 4 9 9 1 2 1 3 2 1 2 2 2 0 2 1 2 2 0 2 1 3 1 0 2 3 3 3 0 2 4 3 4 1 3 2 3 3 0 3 3 4 3 0 4 3 4 4 0 2 2 1 2 4 2 1
输出样例#1:
14
题解:分层图最短路问题。最多就10类门,一看就是状态压缩最大空间 (1<<11)-1 ,很友好...d[i][sta]表示到点i,状态为sta的最短路长度(sta就是到i点前所持有的钥匙的状态)。
代码:
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 #include <queue> 5 #include <cstring> 6 #define CLR(a, b) memset((a), (b), sizeof((a))) 7 using namespace std; 8 const int N = 110; 9 const int states = 1<<11; 10 const int INF = 0x3f3f3f3f; 11 12 int d[N][states], vis[N][states]; 13 int id[N][N]; 14 int key[N]; //key[i]:i点有哪些钥匙(状态) 15 int mp[N][N]; //mp[i][j]:i到j有哪类门 16 int dx[] = {1, 0, -1, 0}; 17 int dy[] = {0, 1, 0, -1}; 18 int n, m, p; 19 struct qnode{ 20 int v; 21 int x;//状态 22 qnode(int _v=0,int _x=0):v(_v),x(_x){} 23 }; 24 bool SPFA(int st, int ed) { 25 CLR(vis, 0); 26 CLR(d, INF); 27 d[st][0] = 0; 28 queue<qnode> q; 29 while(!q.empty()) q.pop(); 30 q.push(qnode(st, 0)); 31 while(!q.empty()) { 32 qnode t = q.front(); q.pop(); 33 int u = t.v; 34 int sta = t.x; 35 vis[u][sta] = false; 36 37 if(key[u]) sta |= key[u]; 38 for(int i = 0; i < 4; i++) { 39 int x = (u+m-1)/m + dx[i]; 40 int y = (u%m?u%m:m) + dy[i]; 41 42 if(x < 1 || x > n || y < 1 || y > m) continue; 43 int v = id[x][y]; 44 //不是墙 并且 有对应钥匙 或者没有门。 45 if(mp[u][v]!=0 && ( (sta&(1<<mp[u][v])) || mp[u][v]==-1)) { 46 if(d[v][sta] > d[u][t.x] + 1) { 47 d[v][sta] = d[u][t.x] + 1; 48 if(!vis[v][sta]) { 49 vis[v][sta] = true; 50 q.push(qnode(v, sta)); 51 } 52 } 53 } 54 } 55 } 56 int ans = INF; 57 for(int i = 0; i < states; ++i) ans = min(ans, d[ed][i]); 58 if(ans == INF) puts("-1"); 59 else printf("%d\n", ans); 60 } 61 int main() { 62 int i, j, k, x1, y1, x2, y2, q, sum; 63 scanf("%d%d%d", &n, &m, &p);//行,列,门和墙的总数 64 65 int cnt = 0; 66 for(i = 1; i <= n; ++i) 67 for(j = 1; j <= m; ++j) id[i][j] = ++cnt; 68 69 CLR(mp, -1); 70 scanf("%d", &k);//门和墙总数 71 for(i = 1; i <= k; ++i) { 72 scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &q); 73 int id1 = id[x1][y1]; 74 int id2 = id[x2][y2]; 75 mp[id1][id2] = mp[id2][id1] = q; 76 } 77 scanf("%d", &sum);//钥匙总数 78 for(i = 1; i <= sum; ++i) { 79 scanf("%d%d%d", &x1, &y1, &q); 80 key[id[x1][y1]] |= (1<<q); 81 } 82 SPFA(1, n*m); 83 return 0; 84 }