[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();}

浙公网安备 33010602011771号