搜索-华容道(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 。

 

  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 }
View Code

 

posted @ 2018-07-25 17:23  derchg  阅读(168)  评论(0编辑  收藏  举报