[NOIP 2013]华容道[搜索][图论]

题面:https://loj.ac/problem/2613


观察可以发现,其实对于一张图,真正有用的信息不过是空格子周围四个格子的信息

而对于空格子从点 $x$ 移动到了 $y$ 点,我们可以把 $y$ 看成是指定格子,这样我们需要维护的信息就是空格在指定格子四周的状态

那我们完全可以把这些状态抽离出来,然后就可以形成一张图,边权就是从一个状态到另一个状态最小需要的步数

那我们假设一个点为指定格子,我们需要维护空格子在他四周的状态,并且需要知道空格子从一个方向跑到了另一个方向需要的最小距离,显然 BFS 即可

我们还需要把这些状态都联通,这种情况其实就是空格子和指定格子交换了位置,边权为1,显然可以维护

那么我们就构建出来了这种图,然后在图上跑一遍最短路就可以是答案了

注意我们回答询问的时候需要先把空格子移到 S 点,这一步可以 BFS,然后再从 S 点跑到 T 的最短路

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cstdlib>
  6 #include <vector>
  7 #include <queue>
  8 #include <cctype>
  9 #define inf 5100
 10 #define ll long long
 11 #define INF 0x7fffffff
 12 #define HINF 0x3f3f3f3f
 13 #define N 51
 14 
 15 namespace chiaro{
 16 
 17 template <class T>
 18 inline void read(T& num) {
 19     num = 0; register char c = getchar(), up = c;
 20     while(!isdigit(c)) up = c, c = getchar();
 21     while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
 22     up == '-' ? num = -num : 0;
 23 }
 24 template <class T>
 25 inline void read(T& a,T& b) {read(a); read(b);}
 26 
 27 inline void setting() {
 28 #ifdef ONLINE_JUDGE
 29     freopen("centroid.in", "r", stdin);
 30     freopen("centroid.out", "w", stdout);
 31 #endif
 32 }
 33 
 34 struct Point{
 35     int x, y;
 36 };
 37 
 38 struct edge {
 39     int to;
 40     int val;
 41     edge* nxt;
 42 };
 43 
 44 struct Node {
 45     int dis;
 46     int pos;
 47     inline bool operator < (const Node& next) const {
 48         return dis > next.dis;
 49     }
 50 };
 51 
 52 const int fx[] = {-1, 0, 1, 0};
 53 const int fy[] = {0, 1, 0, -1};
 54 
 55 int n, m, q;
 56 bool a[N][N];
 57 int predis[N][N], dis[inf];
 58 edge* g[inf << 2];
 59 int idSize;
 60 
 61 inline void connect(int from, int to, int val) {
 62     static edge pool[inf << 2];
 63     static auto p = pool;
 64     p->to = to;
 65     p->val = val;
 66     p->nxt = g[from];
 67     g[from] = p; ++p;
 68     return;
 69 }
 70 
 71 inline Point make_point(int a, int b) {
 72     return (Point){a, b};
 73 }
 74 
 75 inline Node make_node(int a, int b) {
 76     return (Node){a, b};
 77 }
 78 
 79 inline int getid (int x, int y) {
 80     y = ((x - 1) * m + y - 1) << 2;
 81     idSize = std::max (idSize, y);
 82     return y;
 83 }
 84 
 85 inline int getid (Point x) {return getid(x.x, x.y);}
 86 
 87 inline void bfs(Point empty, Point goal) {
 88     static std::queue <Point> Q;
 89     memset(predis, -1, sizeof predis);
 90     predis[empty.x][empty.y] = 0;
 91     predis[goal.x][goal.y] = 1;
 92     Q.push(empty);
 93     while(!Q.empty()) {
 94         Point x = Q.front(); Q.pop();
 95         for(int i = 0; i < 4; i++) {
 96             int nowx = x.x + fx[i];
 97             int nowy = x.y + fy[i];
 98             if(a[nowx][nowy] && predis[nowx][nowy] == -1) {
 99                 predis[nowx][nowy] = predis[x.x][x.y] + 1;
100                 Q.push(make_point(nowx, nowy));
101             }
102         }
103     }
104 }
105 
106 inline void buildGraph(Point empty, Point goal, int k) {
107     int id = getid(goal);
108     for(int i = 0; i < 4; i++) {
109         int x = goal.x + fx[i];
110         int y = goal.y + fy[i];
111         (predis[x][y] > 0) ? connect(id + k, id + i, predis[x][y]), 0 : 0;
112     }
113     connect(id + k, getid(empty) + (k + 2) % 4, 1);
114 }
115 
116 inline void dij(Point s) {
117     static std::priority_queue <Node, std::vector <Node>, std::less<Node>> P;
118     static bool vis[inf];
119     std::fill(vis, vis + 1 + idSize + 4, 0);
120     std::fill(dis, dis + 1 + idSize + 4, HINF);
121     for(int i = 0; i < 4; i++) {
122         int x = s.x + fx[i];
123         int y = s.y + fy[i];
124         if(predis[x][y] == -1) continue;
125         int id = getid(s) + i;
126         dis[id] = predis[x][y];
127         P.push(make_node(0, id));
128     }
129     while(!P.empty()) {
130         int x = P.top().pos; P.pop();
131         if(vis[x]) continue;
132         vis[x] = 1;
133         for(auto e = g[x]; e; e = e->nxt) {
134             int y = e->to;
135             if(dis[y] > dis[x] + e->val) {
136                 dis[y] = dis[x] + e->val;
137                 (vis[y] == 0) ? P.push(make_node(dis[y], y)), 0 : 0;
138             }
139         }
140     }
141     return;
142 }
143 
144 #define min(a, b) ((a) < (b) ? (a) : (b))
145 
146 inline signed main () {
147     read(n, m); read(q);
148     for(int i = 1; i <= n; i++) {
149         for(int j = 1; j <= m; j++) read(a[i][j]);
150     }
151     for(int i = 1; i <= n; i++) {
152         for(int j = 1; j <= m; j++) {
153             if(a[i][j] == 0) continue;
154             for(int k = 0; k < 4; k++) {
155                 if(a[i + fx[k]][j + fy[k]] == 0) continue;
156                 bfs(make_point(i + fx[k], j + fy[k]), make_point(i, j));
157                 buildGraph(make_point(i + fx[k], j + fy[k]), make_point(i, j), k);
158             }
159         }
160     }
161     Point e, s, t;
162     for(int i = 1; i <= q; i++) {
163         read(e.x, e.y);
164         read(s.x, s.y);
165         read(t.x, t.y);
166         if(s.x == t.x && s.y == t.y) {puts("0"); continue;}
167         bfs(e, s);
168         dij(s);
169         int id = getid(t);
170         int ans = INF;
171         for(int i = 0; i < 4; i++) dis[id + i] != HINF ? ans = min (ans, dis[id + i]) : 0;
172         ans == INF ? ans = -1 : 0;
173         printf("%d\n", ans);
174     }
175     return 0;
176 }
177 
178 }
179 
180 signed main() {return chiaro::main();}

 

posted @ 2020-08-28 11:15  Chiaro  阅读(242)  评论(0)    收藏  举报