搜索-华容道(NOIP2013 D2T3)
暴搜可以拿 60 。据说可以用 A* 搜可以拿 100 。我写的是 BFS预处理后SPFA ,跑得还算比较快。
移动过程可以分为两部分:A 空格移动到可移动的棋子四周(过程中不经过该棋子);B 可移动的棋子在空格的“帮助”下到达目标点。对于 A 过程,BFS 处理出到达上下左右的代价到 P[4] 里。对于 B 过程,注意到在已知空格在某位置的可移动棋子的上下左右的某方向上时,先把空格移动到棋子将要移动到的方向,再把棋子向那个方向移动一部的代价是一定的。也就是说,定义状态(节点)dis[x][y][k1][k2] 表示 (x, y) 位置的棋子,当前空格在 k1 方向,然后这颗棋子移动到它的 k2 方向的代价。那么就可以建图。一个点相关的边只会有上下左右四条。然后跑 SPFA 即可。把 B 过程的代价加上对应的 P ,各个情况取最小值就是答案。口胡得稍微有点复杂(我怎么自己也不能理解了),放个代码留给自己以后看。
另外这道题还学到一个奇技淫巧:k = 0, 1, 2, 3 分别表示上下左右,然后希望找一个对应关系 f(上) = 下, f(左) = 右,反过来也是。这样的话这个对应关系 f(k) = k xor 1 。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 5 using namespace std; 6 7 const int INF = 1e9; 8 9 struct node { 10 int x, y, w; 11 node(int x = 0, int y = 0, int w = 0): 12 x(x), y(y), w(w) { } 13 }; 14 15 int nxt[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1}, A[35][35], P[4], dis[35][35][4], W[35][35][4][4]; 16 int N, M, ex, ey, sx, sy, tx, ty; 17 queue<node> Q; 18 bool mk[35][35], mk2[35][35][4]; 19 20 bool Lim(int i, int j, int k) 21 { 22 int x = i+nxt[k][0], y = j+nxt[k][1]; 23 if (x < 1 || x > N || y < 1 || y > M || !A[x][y]) return false; 24 return true; 25 } 26 27 namespace _solve { 28 29 void BFS() 30 { 31 int g, k; 32 for (g = 0; g < 4; ++g) P[g] = INF; 33 memset(mk, 0, sizeof mk); 34 while (!Q.empty()) Q.pop(); 35 Q.push(node(ex, ey, 0)), mk[ex][ey] = mk[sx][sy] = true; 36 for (g = 0; g < 4; ++g) 37 if (ex == sx+nxt[g][0] && ey == sy+nxt[g][1]) P[g] = 0; 38 while (!Q.empty()) { 39 node p = Q.front(); 40 Q.pop(); 41 for (k = 0; k < 4; ++k) { 42 int xx = p.x+nxt[k][0], yy = p.y+nxt[k][1]; 43 if (Lim(p.x, p.y, k) && !mk[xx][yy]) { 44 Q.push(node(xx, yy, p.w+1)), mk[xx][yy] = true; 45 for (g = 0; g < 4; ++g) 46 if (xx == sx+nxt[g][0] && yy == sy+nxt[g][1]) P[g] = p.w+1; 47 } 48 } 49 } 50 return; 51 } 52 53 int SPFA(int KKK) 54 { 55 int i, j, k; 56 if (P[KKK] >= INF) return INF; 57 for (i = 1; i <= N; ++i) 58 for (j = 1; j <= M; ++j) 59 for (k = 0; k < 4; ++k) 60 dis[i][j][k] = INF; 61 memset(mk2, 0, sizeof mk2); 62 while (!Q.empty()) Q.pop(); 63 dis[sx][sy][KKK] = 0, mk2[sx][sy][KKK] = true, Q.push(node(sx, sy, KKK)); 64 while (!Q.empty()) { 65 node p = Q.front(); 66 Q.pop(), mk2[p.x][p.y][p.w] = false; 67 for (k = 0; k < 4; ++k) { 68 int xx = p.x+nxt[k][0], yy = p.y+nxt[k][1]; 69 if (Lim(p.x, p.y, k) && dis[xx][yy][k^1] > dis[p.x][p.y][p.w] + W[p.x][p.y][p.w][k]) { 70 dis[xx][yy][k^1] = dis[p.x][p.y][p.w] + W[p.x][p.y][p.w][k]; 71 if (!mk2[xx][yy][k^1]) mk2[xx][yy][k^1] = true, Q.push(node(xx, yy, k^1)); 72 } 73 } 74 } 75 int mn = INF; 76 for (k = 0; k < 4; ++k) mn = min(mn, dis[tx][ty][k]); 77 return mn+P[KKK]; 78 } 79 80 } 81 82 namespace _init { 83 84 int BFS(int x, int y, int k1, int k2) 85 { 86 int x1 = x+nxt[k1][0], x2 = x+nxt[k2][0], y1 = y+nxt[k1][1], y2 = y+nxt[k2][1], k; 87 while (!Q.empty()) Q.pop(); 88 memset(mk, 0, sizeof mk); 89 Q.push(node(x1, y1, 0)), mk[x1][y1] = mk[x][y] = true; 90 if (x1 == x2 && y1 == y2) return 1; 91 while (!Q.empty()) { 92 node p = Q.front(); 93 Q.pop(); 94 for (k = 0; k < 4; ++k) { 95 int xx = p.x+nxt[k][0], yy = p.y+nxt[k][1]; 96 if (!mk[xx][yy] && Lim(p.x, p.y, k)) { 97 Q.push(node(xx, yy, p.w+1)), mk[xx][yy] = true; 98 if (xx == x2 && yy == y2) return p.w+2; 99 } 100 } 101 } 102 return INF; 103 } 104 105 void Init() 106 { 107 int i, j, k1, k2; 108 for (i = 1; i <= N; ++i) 109 for (j = 1; j <= M; ++j) { 110 if (!A[i][j]) continue; 111 for (k1 = 0; k1 < 4; ++k1) { 112 if (!Lim(i, j, k1)) continue; 113 for (k2 = 0; k2 < 4; ++k2) { 114 if (!Lim(i, j, k2)) continue; 115 W[i][j][k1][k2] = BFS(i, j, k1, k2); 116 } 117 } 118 } 119 } 120 121 } 122 123 int main() 124 { 125 int QUERY, i, j, k; 126 scanf("%d%d%d", &N, &M, &QUERY); 127 for (i = 1; i <= N; ++i) 128 for (j = 1; j <= M; ++j) 129 scanf("%d", &A[i][j]); 130 _init::Init(); 131 while (QUERY--) { 132 scanf("%d%d%d%d%d%d", &ex, &ey, &sx, &sy, &tx, &ty); 133 if (sx == tx && sy == ty) { printf("0\n"); continue; } 134 if (!A[sx][sy]) { printf("-1\n"); continue; } 135 _solve::BFS(); 136 int ans = INF; 137 for (k = 0; k < 4; ++k) { 138 ans = min(ans, _solve::SPFA(k)); 139 } 140 printf("%d\n", ans >= INF ? -1 : ans); 141 } 142 return 0; 143 }