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 }
View Code

然而注意判断答案为0.。。。。。。没判被卡成65分 不如暴力

posted @ 2017-11-02 10:23  Blue233333  阅读(349)  评论(0编辑  收藏  举报