[NOIP2013]华容道 题解(搜索)

 [NOIP2013]华容道

【题目描述】

  这道题根据小时候玩华容道不靠谱的经验还以为是并查集,果断扑街。考后想想也是,数据这么小一定有他的道理。

  首先由于是最小步数,所以BFS没跑了。那么我们大可把这道题分为两部分,首先先把白格子移到目标棋子附近,然后再把目标棋子移过去。第一步是很容易的,随便BFS一下就好了,关键是第二步。由于q不小,我们不可能每次询问都直接爆搜,但由于棋盘并不会发生本质改变,我们可以对一些东西进行预处理。

  那每次询问时不变的是什么呢,我们求第二步时需要的又是什么呢?

  首先我们可以明确的是一个棋子得以移动一定是它移动的目标上是空的,而我们只有一个空格子,所以一旦我们确定了空格子的位置整个棋盘的状态就明了了,所以我们要处理的是当白格子在哪个位置时我想把当前棋子移到上下左右某一位置所要花费的最少步数,那么我们真的需要开5维去表示这一状态吗?不必,四维就够了,对于白格子从之前道这个点附近其实本质和第一步无异,而在我们执行第二步时白格子在每次转移完一定是在目标棋子的上下左右位置,所以我们只需要处理出来目标棋子在当前格子时白格子在他上下左右时他向上下左右移动所耗费的步数即可。

  然后,对于每一次询问,我们可以把每个点拆成四个,即白格子在这个点上下左右时的最小步数,慢慢搞即可。

  对了,提醒一下,对于某个格子进行处理的时候一定不能通过该点进行更新。

  

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<map>
  7 #include<queue>
  8 #include<string>
  9 #include<cmath>
 10 using namespace std;
 11 int n,m,q,a[40][40],zy[5][2],dis[40][40];
 12 struct no{int x,y,k;};
 13 bool check(int x,int y,int z){
 14     if(x+zy[z][0]!=0&&x+zy[z][0]!=n+1&&y+zy[z][1]!=0&&y+zy[z][1]!=m+1&&a[x+zy[z][0]][y+zy[z][1]]) return 1;
 15     return 0;
 16 }
 17 bool fw[40][40],f2[40][40];
 18 int f[40][40][5][5];
 19 void bfs1(int ax,int by){
 20     memset(dis,0x3f,sizeof(dis));
 21     memset(fw,0,sizeof(fw));
 22     queue<no> q1;
 23     no aa;
 24     aa.x=ax,aa.y=by;
 25     dis[ax][by]=0;
 26     q1.push(aa);
 27     fw[ax][by]=1;
 28     while(!q1.empty())
 29     {
 30         no t=q1.front();
 31         q1.pop();
 32         int x=t.x,y=t.y;
 33         for(int i=1;i<=4;i++)
 34         {
 35             int xx=x+zy[i][0],yy=y+zy[i][1];
 36             if(xx==0||xx==n+1||yy==0||yy==m+1) continue;
 37             if(!a[xx][yy]) continue;
 38             if(f2[xx][yy]) continue;
 39             if(dis[xx][yy]>dis[x][y]+1)
 40             {
 41                 dis[xx][yy]=dis[x][y]+1;
 42                 if(!fw[xx][yy])
 43                 {
 44                     fw[xx][yy]=1;
 45                     no bb;
 46                     bb.x=xx,bb.y=yy;
 47                     q1.push(bb);
 48                 }
 49             }
 50         }
 51     }
 52 }
 53 bool rd[40][40][4];
 54 int dis2[40][40][5];
 55 void spfa(int ax,int by){
 56     memset(rd,0,sizeof(rd));
 57     no aa;
 58     queue<no> q1;
 59     aa.x=ax,aa.y=by;
 60     if(check(ax,by,1))
 61     {   
 62         aa.k=1;
 63         q1.push(aa);
 64         rd[ax][by][1]=1;
 65     }
 66     if(check(ax,by,2))
 67     {
 68         aa.k=2;
 69         q1.push(aa);
 70         rd[ax][by][2]=1;
 71     }
 72     if(check(ax,by,3))
 73     {
 74         aa.k=3;
 75         q1.push(aa);
 76         rd[ax][by][3]=1;
 77     }
 78     if(check(ax,by,4))
 79     {
 80         aa.k=4;
 81         q1.push(aa);
 82         rd[ax][by][4]=1;
 83     }
 84     while(!q1.empty())
 85     {
 86         no bb=q1.front();q1.pop();
 87         int x=bb.x,y=bb.y,k=bb.k;
 88         rd[x][y][k]=0;
 89         if(check(x,y,1)&&dis2[x-1][y][2]>dis2[x][y][k]+f[x][y][1][k]&&f[x][y][1][k]!=-1)
 90         {
 91             dis2[x-1][y][2]=dis2[x][y][k]+f[x][y][1][k];
 92             if(!rd[x-1][y][2])
 93             {
 94                 rd[x-1][y][2]=1;
 95                 no cc;
 96                 cc.x=x-1,cc.y=y,cc.k=2;
 97                 q1.push(cc);
 98             }
 99         }
100         if(check(x,y,2)&&dis2[x+1][y][1]>dis2[x][y][k]+f[x][y][2][k]&&f[x][y][2][k]!=-1)
101         {
102             dis2[x+1][y][1]=dis2[x][y][k]+f[x][y][2][k];
103             if(!rd[x+1][y][1])
104             {
105                 rd[x+1][y][1]=1;
106                 no cc;
107                 cc.x=x+1,cc.y=y,cc.k=1;
108                 q1.push(cc);
109             }
110         }
111         if(check(x,y,3)&&dis2[x][y-1][4]>dis2[x][y][k]+f[x][y][3][k]&&f[x][y][3][k]!=-1)
112         {
113             dis2[x][y-1][4]=dis2[x][y][k]+f[x][y][3][k];
114             if(!rd[x][y-1][4])
115             {
116                 rd[x][y-1][4]=1;
117                 no cc;
118                 cc.x=x,cc.y=y-1,cc.k=4;
119                 q1.push(cc);
120             }
121         }
122         if(check(x,y,4)&&dis2[x][y+1][3]>dis2[x][y][k]+f[x][y][4][k]&&f[x][y][4][k]!=-1)
123         {
124             dis2[x][y+1][3]=dis2[x][y][k]+f[x][y][4][k];
125             if(!rd[x][y+1][3])
126             {
127                 rd[x][y+1][3]=1;
128                 no cc;
129                 cc.x=x,cc.y=y+1,cc.k=3;
130                 q1.push(cc);
131             }
132         }
133     }
134 }
135 int main(){
136     memset(f,-1,sizeof(f));
137     scanf("%d%d%d",&n,&m,&q);
138     for(int i=1;i<=n;i++)
139         for(int j=1;j<=m;j++)
140             scanf("%d",&a[i][j]);
141     zy[1][0]=-1,zy[2][0]=1;
142     zy[3][1]=-1,zy[4][1]=1;
143     for(int i=1;i<=n;i++)
144     {
145         for(int j=1;j<=m;j++)
146         {
147             if(!a[i][j]) continue;
148             f2[i][j]=1;
149             for(int k=1;k<=4;k++)
150             {      
151                 if(check(i,j,k))
152                 {
153                     bfs1(i+zy[k][0],j+zy[k][1]);
154                     for(int l=1;l<=4;l++)
155                     {
156                         if(check(i,j,l)&&dis[i+zy[l][0]][j+zy[l][1]]!=dis[0][0])
157                             f[i][j][l][k]=dis[i+zy[l][0]][j+zy[l][1]]+1;
158                     }
159                 }
160             }
161             f2[i][j]=0;
162         }
163     }
164      
165     for(int i=1;i<=q;i++)
166     {
167         int ex,ey,sx,sy,tx,ty;
168         scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
169         if(tx==sx&&ty==sy)
170         {
171             printf("0
");
172             continue;
173         }
174         memset(dis2,0x3f,sizeof(dis2));
175         memset(f2,0,sizeof(f2));
176         f2[sx][sy]=1;
177         bfs1(ex,ey);
178         bool yx=0;
179         for(int j=1;j<=4;j++)
180         {
181             if(check(sx,sy,j)&&dis[sx+zy[j][0]][sy+zy[j][1]]!=dis[0][0])
182             {
183                 yx=1;
184                 dis2[sx][sy][j]=dis[sx+zy[j][0]][sy+zy[j][1]];
185             }
186         }
187         if(!yx)
188         {
189             printf("-1
");
190             continue;
191         }
192         spfa(sx,sy);
193         int ans=0x7fffffff;
194         for(int j=1;j<=4;j++)
195             ans=min(ans,dis2[tx][ty][j]);
196         if(ans==0x7fffffff||ans==dis2[0][0][0])
197         {
198             printf("-1
");
199             continue;
200         }
201         else
202             printf("%d
",ans);
203     }
204     return 0;
205 }
View Code
原文地址:https://www.cnblogs.com/liutianrui/p/7403687.html