1. 程式人生 > >Luogu1979 NOIP2013D2T3 華容道 搜索、SPFA

Luogu1979 NOIP2013D2T3 華容道 搜索、SPFA

blank 最短路 能夠 targe www. 發揮 front git air

題目傳送門

題意:給出一個$N \times M$的棋盤,棋盤上有一些塊可以移動,有一些塊無法移動。$Q$次詢問,每一次詢問給出三個塊$a,b,c$,將$a$塊變為空格,空格旁邊可移動的塊可以與空格交換位置。問每一次詢問中最小的將$b$塊移動到$c$塊最開始位置上的移動次數。$N , M \leq 30 , Q \leq 500$


我覺得我在$NOIP$考場上絕對會直接打暴力qwq

我們能夠發現空格必須要在需要移動的格子的四周,而且不移動需要移動的格子,才能發揮效果。所以當空格在需要移動的格子旁邊的時候,只有兩種情況:①將需要移動的格子與空格交換位置;②將空格移動到需要移動的格子的另一側。所以我們預處理:$f_{i,j,k,l}$表示將空格從格子$i,j$的方向$k$移動到方向$l$且不移動$(i,j)$的最少步數,可以通過$bfs$實現,復雜度$O(16N^2M^2)$

接下來就是一個類似於最短路的問題了。然而最開始空格與需要移動的格子不相鄰,所以我們在每一次詢問的時候,再一次$bfs$計算現在空格的位置到達需要移動的格子四周且不移動需要移動的格子的最少移動次數,然後跑$SPFA$即可。因為圖很小,卡不了$SPFA$。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 inline int read(){
  5     int a = 0;
  6     char c = getchar();
  7     while(!isdigit(c))
  8         c = getchar();
9 while(isdigit(c)){ 10 a = (a << 3) + (a << 1) + (c ^ 0); 11 c = getchar(); 12 } 13 return a; 14 } 15 16 const int dir[4][2] = {0,1,1,0,-1,0,0,-1}; 17 int f[31][31][4][4] , dis[31][31][4] , t[31][31] , N , M , Q; 18 bool canbe[32][32] , inq[31][31][4];
19 struct be{ 20 int x , y , dir; 21 }now; 22 23 queue < pair < int , int > > q; 24 queue < be > q1; 25 26 inline int SPFA(int aX , int aY , int bX , int bY , int cX , int cY){ 27 while(!q.empty()) 28 q.pop(); 29 if(!canbe[aX][aY] || !canbe[bX][bY]) 30 return 0x3f3f3f3f; 31 memset(t , 0x3f , sizeof(t)); 32 t[aX][aY] = 0; 33 q.push(make_pair(aX , aY)); 34 while(!q.empty()){ 35 pair < int , int > r = q.front(); 36 q.pop(); 37 if(r.first == bX && r.second == bY) 38 return t[bX][bY]; 39 for(int i = 0 ; i < 4 ; i++) 40 if(r.first + dir[i][0] != cX || r.second + dir[i][1] != cY) 41 if(canbe[r.first + dir[i][0]][r.second + dir[i][1]]) 42 if(t[r.first + dir[i][0]][r.second + dir[i][1]] > t[r.first][r.second] + 1){ 43 t[r.first + dir[i][0]][r.second + dir[i][1]] = t[r.first][r.second] + 1; 44 q.push(make_pair(r.first + dir[i][0] , r.second + dir[i][1])); 45 } 46 } 47 return 0x3f3f3f3f; 48 } 49 50 inline void bfs(int sX , int sY , int tX , int tY){ 51 for(int i = 0 ; i < 4 ; i++) 52 if(dis[sX][sY][i] != 0x3f3f3f3f){ 53 inq[sX][sY][i] = 1; 54 q1.push((be){sX , sY , i}); 55 } 56 while(!q1.empty()){ 57 now = q1.front(); 58 inq[now.x][now.y][now.dir] = 0; 59 q1.pop(); 60 if(now.x == tX && now.y == tY) 61 continue; 62 for(int i = 0 ; i < 4 ; i++) 63 if(now.dir != i){ 64 int N = dis[now.x][now.y][now.dir] + f[now.x][now.y][now.dir][i]; 65 if(dis[now.x][now.y][i] > N){ 66 dis[now.x][now.y][i] = N; 67 if(!inq[now.x][now.y][i]){ 68 inq[now.x][now.y][i] = 1; 69 q1.push((be){now.x , now.y , i}); 70 } 71 } 72 } 73 if(dis[now.x + dir[now.dir][0]][now.y + dir[now.dir][1]][3 - now.dir] > dis[now.x][now.y][now.dir] + 1){ 74 dis[now.x + dir[now.dir][0]][now.y + dir[now.dir][1]][3 - now.dir] = dis[now.x][now.y][now.dir] + 1; 75 if(!inq[now.x + dir[now.dir][0]][now.y + dir[now.dir][1]][3 - now.dir]){ 76 inq[now.x + dir[now.dir][0]][now.y + dir[now.dir][1]][3 - now.dir] = 1; 77 q1.push((be){now.x + dir[now.dir][0] , now.y + dir[now.dir][1] , 3 - now.dir}); 78 } 79 } 80 } 81 } 82 83 int main(){ 84 N = read(); 85 M = read(); 86 Q = read(); 87 for(int i = 1 ; i <= N ; i++) 88 for(int j = 1 ; j <= M ; j++) 89 canbe[i][j] = read(); 90 memset(f , 0x3f , sizeof(f)); 91 for(int i = 1 ; i <= N ; i++) 92 for(int j = 1 ; j <= M ; j++) 93 if(canbe[i][j]) 94 for(int m = 0 ; m <= 3 ; m++) 95 for(int n = 0 ; n <= 3 ; n++) 96 f[i][j][m][n] = SPFA(i + dir[m][0] , j + dir[m][1] , i + dir[n][0] , j + dir[n][1] , i , j); 97 while(Q--){ 98 int a = read() , b = read() , c = read() , d = read() , e = read() , f = read(); 99 if(c == e && d == f){ 100 printf("0\n"); 101 continue; 102 } 103 memset(dis , 0x3f , sizeof(dis)); 104 for(int i = 0 ; i < 4 ; i++) 105 dis[c][d][i] = SPFA(a , b , c + dir[i][0] , d + dir[i][1] , c , d); 106 bfs(c , d , e , f); 107 int ans = 0x3f3f3f3f; 108 for(int i = 0 ; i < 4 ; i++) 109 ans = min(ans , dis[e][f][i]); 110 printf("%d\n" , ans == 0x3f3f3f3f ? -1 : ans); 111 } 112 return 0; 113 }

Luogu1979 NOIP2013D2T3 華容道 搜索、SPFA