NOIP2013提高组D2T3 华容道
n<=30 * m<=30 的地图上,0表示墙壁,1表示可以放箱子的空地。q<=500次询问,每次问:当空地上唯一没有放箱子的空格子在(ex,ey)时,把位于(sx,sy)的箱子移动到(tx,ty)的最小步数。
第一档:n<=10,m<=10,不加剪枝地乱搞??
第二档:n<=30,m<=30,q<=10,直接搜索,我觉得这60分够多了。。
所有档:
完成移动需要两个过程:空白格移动到指定箱子的周围(不能经过指定箱子),指定箱子在空白格的配合下逐渐逼近目标格子。
前者可以直接搜索得到,而后者比较麻烦。为了配合指定箱子,空白格必须时刻在指定箱子周围运动,也就是说,他会从指定箱子的上/下/左/右用最小代价移动到箱子的其他方位,然后让箱子朝那个方向前进一格。
这样的话,实际上是三元状态(x,y,z),(x,y)是当前指定箱子的坐标,z是空格子相对他的方位,这样一些状态之间走来走去,最终走道(tx,ty,上下左右),问最小代价。
可以发现状态之间走来走去的规则非常简单:一个是(x,y,上)转移成(x-1,y,下)这样的不同格子的相反空格方位的移动,另一种是(x,y,上)转移到(x,y,左)这样的同个格子、空格不同方位的转移。
同个格子不同方位间转移的代价可以bfs预处理,而,最后查最小代价只需要一次最短路。
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<stdlib.h> 5 #include<algorithm> 6 #include<queue> 7 //#include<iostream> 8 using namespace std; 9 10 //预处理1:play[i][j][0-3][0-3]表示格子(i,j)的上0下1左2右3到上下左右的不经过格(i,j)的最小移动步数 11 //最短路 12 13 bool isdigit(char c) {return c>='0' && c<='9';} 14 int qread() 15 { 16 char c;int s=0;while (!isdigit(c=getchar())); 17 do s=s*10+c-'0'; while (isdigit(c=getchar()));return s; 18 } 19 20 const int inf=0x3f3f3f3f; 21 int n,m,Q; 22 int mp[33][33],play[33][33][4][4]; 23 const int dx[]={-1,1,0,0},dy[]={0,0,-1,1}; 24 struct qnode1 25 { 26 int x,y,d; 27 }que1[33*33];int head,tail;bool vis1[33][33]; 28 void pre(int x,int y) 29 { 30 mp[x][y]=0; 31 for (int i=0;i<4;i++) 32 for (int j=0;j<4;j++) 33 { 34 if (i==j) {play[x][y][i][j]=0;continue;} 35 if (x+dx[i]<1 || x+dx[i]>n || y+dy[j]<1 || y+dy[j]>m || 36 !mp[x+dx[i]][y+dy[i]] || !mp[x+dx[j]][y+dy[j]]) 37 {play[x][y][i][j]=inf;continue;} 38 play[x][y][i][j]=inf; 39 head=tail=0; 40 que1[tail].d=0,que1[tail].x=x+dx[i],que1[tail++].y=y+dy[i]; 41 memset(vis1,0,sizeof(vis1));vis1[x+dx[i]][y+dy[i]]=1; 42 while (head!=tail) 43 { 44 const int nx=que1[head].x,ny=que1[head].y,nd=que1[head].d;head++; 45 if (nx==x+dx[j] && ny==y+dy[j]) 46 { 47 play[x][y][i][j]=nd; 48 break; 49 } 50 for (int k=0;k<4;k++) 51 { 52 int xx=nx+dx[k],yy=ny+dy[k]; 53 if (xx<1 || xx>n || yy<1 || yy>m || !mp[xx][yy] || vis1[xx][yy]) continue; 54 vis1[xx][yy]=1; 55 que1[tail].x=xx,que1[tail].y=yy;que1[tail++].d=nd+1; 56 } 57 } 58 } 59 mp[x][y]=1; 60 } 61 int road(int sx,int sy,int tx,int ty) 62 { 63 if (tx==sx && ty==sy) return 0; 64 head=tail=0; 65 que1[tail].d=0,que1[tail].x=sx,que1[tail++].y=sy; 66 memset(vis1,0,sizeof(vis1));vis1[sx][sy]=1; 67 while (head!=tail) 68 { 69 const int nx=que1[head].x,ny=que1[head].y,nd=que1[head].d;head++; 70 if (nx==tx && ny==ty) return nd; 71 for (int i=0;i<4;i++) 72 { 73 int xx=nx+dx[i],yy=ny+dy[i]; 74 if (xx<1 || xx>n || yy<1 || yy>m || !mp[xx][yy] || vis1[xx][yy]) continue; 75 vis1[xx][yy]=1; 76 que1[tail].d=nd+1;que1[tail].x=xx;que1[tail++].y=yy; 77 } 78 } 79 return inf; 80 } 81 int dis[33][33][4];bool vis[33][33][4]; 82 struct qnode 83 { 84 int x,y,z,d; 85 bool operator > (const qnode &b) const {return d>b.d;} 86 }; 87 priority_queue<qnode,vector<qnode>,greater<qnode> > q; 88 void work() 89 { 90 int ex=qread(),ey=qread(),sx=qread(),sy=qread(),tx=qread(),ty=qread(); 91 if (sx==tx && sy==ty) 92 { 93 puts("0"); 94 return; 95 } 96 for (int i=1;i<=n;i++) 97 for (int j=1;j<=m;j++) 98 for (int k=0;k<4;k++) 99 dis[i][j][k]=inf; 100 for (int i=0;i<4;i++) 101 { 102 int xx=sx+dx[i],yy=sy+dy[i]; 103 if (xx<1 || xx>n || yy<1 || yy>m || !mp[xx][yy]) continue; 104 mp[sx][sy]=0; 105 dis[sx][sy][i]=road(ex,ey,sx+dx[i],sy+dy[i]); 106 mp[sx][sy]=1; 107 if (dis[sx][sy][i]<inf) q.push((qnode){sx,sy,i,dis[sx][sy][i]}); 108 } 109 memset(vis,0,sizeof(vis)); 110 while (!q.empty()) 111 { 112 const int x=q.top().x,y=q.top().y,z=q.top().z,d=q.top().d;q.pop(); 113 if (vis[x][y][z]) continue; 114 vis[x][y][z]=1; 115 if (z==0 && x>1 && mp[x-1][y]) 116 if (dis[x-1][y][1]>d+1) 117 { 118 dis[x-1][y][1]=d+1; 119 q.push((qnode){x-1,y,1,d+1}); 120 } 121 if (z==1 && x<n && mp[x+1][y]) 122 if (dis[x+1][y][0]>d+1) 123 { 124 dis[x+1][y][0]=d+1; 125 q.push((qnode){x+1,y,0,d+1}); 126 } 127 if (z==2 && y>1 && mp[x][y-1]) 128 if (dis[x][y-1][3]>d+1) 129 { 130 dis[x][y-1][3]=d+1; 131 q.push((qnode){x,y-1,3,d+1}); 132 } 133 if (z==3 && y<m && mp[x][y+1]) 134 if (dis[x][y+1][2]>d+1) 135 { 136 dis[x][y+1][2]=d+1; 137 q.push((qnode){x,y+1,2,d+1}); 138 } 139 for (int i=0;i<4;i++) if (i!=z) 140 if (dis[x][y][i]>d+play[x][y][z][i]) 141 { 142 dis[x][y][i]=d+play[x][y][z][i]; 143 q.push((qnode){x,y,i,d+play[x][y][z][i]}); 144 } 145 } 146 int ans=min(dis[tx][ty][0],min(dis[tx][ty][1],min(dis[tx][ty][2],dis[tx][ty][3]))); 147 printf("%d\n",(ans)>=inf?-1:ans); 148 } 149 int main() 150 { 151 n=qread(),m=qread(),Q=qread(); 152 for (int i=1;i<=n;i++) 153 for (int j=1;j<=m;j++) 154 mp[i][j]=qread(); 155 for (int i=1;i<=n;i++) 156 for (int j=1;j<=m;j++) 157 if (mp[i][j]) 158 pre(i,j); 159 while (Q--) work(); 160 return 0; 161 }
然而注意判断答案为0.。。。。。。没判被卡成65分 不如暴力