【NOIP2013】 华容道 bfs预处理+bfs

这一题我们考虑一个最裸的算法:

我们设$dp[i][j][k][l]$表示当前棋子在$(i,j)$且空格在$(k,l)$时的最小步数

然后显然随便转移一下就好了,时间复杂度为$O(q(nm)^2)$。可以获得$80$分的好成绩(我自测的时候只打了这个)

我们发现这一题有一些很优秀的性质:

首先整个图是静态的,且起点,终点,出现空格的位置均非障碍物。

那么对于这个性质,我们做一些微小的预处理。

考虑到当空格与目标棋子四相邻的时候,棋子才能往空格内移动。那么整个走棋的过程可以理解为:调整空格位置-移动棋子到空格里-调整空格位置

我们设$f[i][j][k][l]$表示在不经过$(i,j)$的情况下,将空格从$(i+wx[k],j+wy[k])$移动到$(i+wx[l],j+wy[l])$的最小步数,其中$wx,wy$满足$|wx[i]+wy[i]|=1$,显然有四种组合。

对于每一个$f[i][j][k][l]$,我们通过一次$bfs$去求解。

预处理$f$的时间复杂度显然为$O(16nm)$。

下面考虑每一组询问:

若起点和终点的坐标相同,那么显然输出$0$就好了。

若起点和终点坐标不相同,我们先考虑将空格移动到起点四相邻的位置,所需要的最小步数显然可以通过一次$bfs$求得。

然后我们设$d[i][j][k]$表示当前棋子在$(i,j)$时,空格在$(i+wx[k],j+wy[k])$的最小步数。

显然随便$bfs$就可以进行更新了。最后的答案显然是$min(d[tx][ty][])$。

时间复杂度$O(16nm+4qnm)$。跑得飞快。

 

  1 #include<bits/stdc++.h>
  2 #define M 32
  3 #define INF 16843009
  4 using namespace std;
  5 int n,m,q,mp[M][M]={0},dis[M][M]={0},d[M][M][4]={0},f[M][M][4][4]={0};
  6 const int wx[]={0,1,0,-1};
  7 const int wy[]={1,0,-1,0};
  8 queue<int> qx,qy,qk;
  9 void bfs(int X,int Y){
 10     memset(dis,1,sizeof(dis));
 11     qx.push(X); qy.push(Y); dis[X][Y]=0;
 12     while(!qx.empty()){
 13         X=qx.front(); qx.pop();
 14         Y=qy.front(); qy.pop();
 15         for(int i=0;i<4;i++){
 16             int _x=X+wx[i],_y=Y+wy[i];
 17             if(mp[_x][_y]&&dis[_x][_y]>dis[X][Y]+1){
 18                 dis[_x][_y]=dis[X][Y]+1;
 19                 qx.push(_x); qy.push(_y);
 20             }
 21         }
 22     }
 23 }
 24 void move(int x,int y){
 25     memset(dis,1,sizeof(dis));
 26     qx.push(x); qy.push(y); dis[x][y]=0;
 27     while(!qx.empty()){
 28         x=qx.front(); qx.pop();
 29         y=qy.front(); qy.pop();
 30         for(int i=0;i<4;i++){
 31             int _x=x+wx[i],_y=y+wy[i];
 32             if(mp[_x][_y]&&dis[_x][_y]>dis[x][y]+1){
 33                 dis[_x][_y]=dis[x][y]+1;
 34                 qx.push(_x); qy.push(_y);
 35             }
 36         }
 37     }
 38 }
 39 
 40 
 41 void bfs(){
 42     while(!qx.empty()){
 43         int x=qx.front(); qx.pop();
 44         int y=qy.front(); qy.pop();
 45         int k=qk.front(); qk.pop();
 46         for(int i=0;i<4;i++){
 47             int _x=x+wx[i],_y=y+wy[i];
 48             if(mp[_x][_y]==0) continue;
 49             if(d[_x][_y][(i+2)&3]>d[x][y][k]+f[x][y][k][i]+1){
 50                 d[_x][_y][(i+2)&3]=d[x][y][k]+f[x][y][k][i]+1;
 51                 qx.push(_x); qy.push(_y); qk.push((i+2)&3);
 52             }
 53         }
 54     }
 55 }
 56             
 57 int main(){
 58     scanf("%d%d%d",&n,&m,&q);
 59     for(int i=1;i<=n;i++)
 60     for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]);
 61     
 62     for(int i=1;i<=n;i++)
 63     for(int j=1;j<=m;j++)
 64     if(mp[i][j]){
 65         mp[i][j]=0;
 66         for(int k=0;k<4;k++)
 67         if(mp[i+wx[k]][j+wy[k]]){
 68             bfs(i+wx[k],j+wy[k]);
 69             for(int l=0;l<4;l++)
 70             f[i][j][k][l]=dis[i+wx[l]][j+wy[l]];
 71         }
 72         mp[i][j]=1;
 73     }
 74     
 75     while(q--){
 76         int ex,ey,sx,sy,tx,ty;
 77         cin>>ex>>ey>>sx>>sy>>tx>>ty;
 78         if(sx==tx&&sy==ty){
 79             printf("0\n");
 80             continue;
 81         }
 82         mp[sx][sy]=0;
 83         move(ex,ey);
 84         mp[sx][sy]=1;
 85         memset(d,1,sizeof(d));
 86         for(int i=0;i<4;i++)
 87         if(mp[sx+wx[i]][sy+wy[i]]){
 88             qx.push(sx);
 89             qy.push(sy);
 90             qk.push(i);
 91             d[sx][sy][i]=dis[sx+wx[i]][sy+wy[i]];
 92         }
 93         bfs();
 94         int minn=INF;
 95         for(int i=0;i<4;i++)
 96         minn=min(minn,d[tx][ty][i]);
 97         if(minn==INF) printf("-1\n");
 98         else cout<<minn<<endl;
 99     }
100 }
posted @ 2018-10-12 10:51  AlphaInf  阅读(350)  评论(0编辑  收藏  举报