1442. [NOIP2013]华容道
★★★ 输入文件:PuzzleNOIP2013.in
输出文件:PuzzleNOIP2013.out
简单对比
时间限制:1 s 内存限制:128 MB
【题目描述】
【输入格式】
输入文件改为:PuzzleNOIP2013.in
【输出格式】
输出文件改为:PuzzleNOIP2013.out
【来源】
CCF全国信息学奥林匹克联赛(NOIP2013)复赛Day2
这道题是一道搜索题,部分分不明确,爆搜可以拿到70分,预处理一下ac。
考虑我们应该如何搜索,对于被标记的格子(下记为x),如果他想往下面走,那么必须先让白格子到达他的下面,其他位置也是同理,当白格子到达他的相邻格子时,x与白格子再交换,所需要的总步数是白格子移动的步数+1,而白格子如何移动呢?我们可以发现,白格子右边的格子往左其实相当于白格子往右,于是我们可以直接视为白格子一步一步移动到指定位置,但需要注意的是,白格子移动过程中不能经过x,于是我们就得到了一个70分的算法,对于初始状态,记录白格子位置,以及x当前的位置,分别向上下左右四个方向bfs,
开一个数组记录到达当前位置最少步数是多少,每次再求出白格子移动所需要的步数,更新数组,一直搜下去即可,类似于spfa吧,但有一个地方需要注意,我们不能单单记录到达xy这个位置时最小步数是多少,而是需要记录到达xy时白格子在i方向时最小步数是多少,不然会出现一种情况:我当前到达xy这个位置步数虽然很少,但我白格子的位置不好,以至于我下一步需要移动很多,导致总步数不是最优。
对于100分,我们可以提前预处理处白格子移动所需要的步数,考虑到x所在位置对白格子移动的影响,并且考虑到时间的问题,我们开一个数组w[i][j][k][o]表示当前位置x在ij,白格子在x的k方向,移动到o方向需要多少步,因为除了初始状态,其他状态白格子总在x格子的旁边4个位置,所以我们对白格子初始位置暴力搜一下搜到x初始位置的周围,然后再搜,白格子移动距离直接调用即可。
但是需要注意一种情况,就是x的初始位置和目标位置是同一个位置,这种情况就直接输出0即可。
贴上代码,因为对着70分改的,所以巨丑无比


1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,q,a[31][31],b[31][31],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},w[31][31][4][4]; 4 struct hh{ 5 int x,y,z,step; 6 hh(){} 7 hh(int a,int b,int c,int d){ 8 x=a;y=b;z=c;step=d; 9 } 10 hh(int a,int b,int c){ 11 x=a;y=b;step=c; 12 } 13 }; 14 void bfs(int x,int y,int p,int q,int z){ 15 bool vi[31][31];memset(vi,0,sizeof(vi)); 16 int dis[31][31];memset(dis,-1,sizeof(dis)); 17 queue<hh>S;S.push(hh(x,y,0)); 18 vi[p][q]=1;vi[x][y]=1; 19 dis[x][y]=0; 20 while(!S.empty()){ 21 hh u=S.front();S.pop(); 22 for(int i=0;i<4;i++){ 23 int tem1=dx[i]+u.x; 24 int tem2=dy[i]+u.y; 25 if(!b[tem1][tem2])continue; 26 if(!a[tem1][tem2])continue; 27 if(vi[tem1][tem2])continue; 28 vi[tem1][tem2]=1; 29 S.push(hh(tem1,tem2,u.step+1)); 30 dis[tem1][tem2]=u.step+1; 31 } 32 } 33 for(int i=0;i<4;i++){ 34 int tem1=p+dx[i]; 35 int tem2=q+dy[i]; 36 if(!a[tem1][tem2])continue; 37 if(!b[tem1][tem2])continue; 38 w[p][q][z][i]=dis[tem1][tem2]; 39 } 40 } 41 int get(int q,int w,int e,int r,int x,int y){ 42 queue<hh>S; 43 bool vi[31][31];memset(vi,0,sizeof(vi)); 44 vi[q][w]=1;vi[x][y]=1; 45 S.push(hh(q,w,0)); 46 while(!S.empty()){ 47 hh u=S.front(); 48 S.pop(); 49 if(u.x==e&&u.y==r){ 50 return u.step; 51 } 52 for(int i=0;i<4;i++){ 53 int tem1=u.x+dx[i]; 54 int tem2=u.y+dy[i]; 55 if(!a[tem1][tem2])continue; 56 if(!b[tem1][tem2])continue; 57 if(vi[tem1][tem2])continue; 58 vi[tem1][tem2]=1; 59 S.push(hh(tem1,tem2,u.step+1)); 60 } 61 }return -1; 62 } 63 int main() 64 { 65 freopen("PuzzleNOIP2013.in","r",stdin); 66 freopen("PuzzleNOIP2013.out","w",stdout); 67 scanf("%d%d%d",&n,&m,&q); 68 for(int i=1;i<=n;i++){ 69 for(int j=1;j<=m;j++){ 70 scanf("%d",&a[i][j]); 71 b[i][j]=1; 72 } 73 } 74 memset(w,-1,sizeof(w)); 75 for(int i=1;i<=n;i++){ 76 for(int j=1;j<=m;j++){ 77 if(!a[i][j])continue; 78 for(int k=0;k<4;k++){ 79 int tem1=dx[k]+i; 80 int tem2=dy[k]+j; 81 if(!a[tem1][tem2])continue; 82 if(!b[tem1][tem2])continue; 83 bfs(tem1,tem2,i,j,k); 84 } 85 } 86 } 87 for(int o=1;o<=q;o++){ 88 int ex,ey,sx,sy,tx,ty,Min=0x3fffffff; 89 scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); 90 queue<hh>S;int vis[31][31][4];if(sx==tx&&sy==ty){ 91 printf("%d\n",0); 92 continue; 93 } 94 memset(vis,0x3f,sizeof(vis)); 95 for(int i=0;i<4;i++){ 96 int tem1=dx[i]+sx; 97 int tem2=dy[i]+sy; 98 if(!a[tem1][tem2])continue; 99 if(!b[tem1][tem2])continue; 100 int l=get(tem1,tem2,ex,ey,sx,sy); 101 if(l==-1)continue; 102 vis[sx][sy][i]=l; 103 S.push(hh(sx,sy,i,l)); 104 } 105 while(!S.empty()){ 106 hh u=S.front(); 107 S.pop(); 108 if(u.x==tx&&u.y==ty){ 109 Min=min(Min,u.step); 110 continue; 111 } 112 for(int i=0;i<4;i++){ 113 int tem1=dx[i]+u.x; 114 int tem2=dy[i]+u.y; 115 if(!b[tem1][tem2])continue; 116 if(!a[tem1][tem2])continue; 117 int l=w[u.x][u.y][u.z][i]; 118 if(l==-1)continue; 119 //cout<<u.z<<" "<<u.x<<" "<<u.y<<" "<<u.step<<endl; 120 if(vis[tem1][tem2][i^1]<=u.step+1+l)continue; 121 vis[tem1][tem2][i^1]=u.step+1+l; 122 S.push(hh(tem1,tem2,i^1,u.step+1+l)); 123 } 124 } 125 if(Min!=0x3fffffff)printf("%d\n",Min); 126 else printf("%d\n",-1); 127 } 128 return 0; 129 }