NOIP[2013] 华容道
Posted TSOI_Vergil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP[2013] 华容道相关的知识,希望对你有一定的参考价值。
一道能够让人深刻理解“状态“含义的图论题目。首先一个很简单的做法就是暴力BFS,以空格子为起点进行BFS,需要记录的有2个量:空格子的位置和目标棋子的位置,我们考虑这样的复杂度,由于是BFS,每个节点只会被访问一次,不同的节点数有n*m*n*m个,再算上q组询问,复杂度为q*n*m*n*m。可以拿到60分。
其实我们有很多状态都是没有必要的,题目中的q组询问中的地图是不会改变的,于是我们考虑先预处理再搞,我们可以知道只有当一个棋子四周存在空格子时,这个棋子才能移动,那么我们可以考虑一个状态F[i][j][k][h],表示从(i,j)这个位置,空格子在它的k方向,它要向h方向移动所需要的最少步数,这个我们可以提前用BFS求出,我们可以把格子(i,j)的K方向上是空格子当成一个状态,记作(i,j,k),那么对于一个F[i][j][k][h]来说,它就是连接(i,j,k)和(i+dx[h],j+dy[h],h的相反方向)的边的边权,这样我们先提前用BFS求出F[i][j][k][h],复杂度是O(n*m*4*4),然后对于每组询问,我们求出那个空格子到达起点格子四周的步数,然后连边,然后再跑一下spfa,复杂度大概是O(q*n*m*4*k)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000005
int pre[maxn],last[maxn],other[maxn],len[maxn],dist[maxn];
int qx[maxn],qy[maxn],n,m,q,tot,cnt,que[maxn],l,S,T;
int f[31][31][5][5],g[31][31],vis[31][31],dis[32][32],id[31][31][5];
bool flag[maxn];
const int dx[5]=0,1,0,0,-1;
const int dy[5]=0,0,1,-1,0;
bool pd(int x,int y)
if (x<1||x>n||y<1||y>m) return 1;
if (g[x][y]==0) return 1;
return 0;
void connect(int x,int y,int z)
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
len[l]=z;
int bfs(int sx,int sy,int tx,int ty)
if (sx==tx&&sy==ty) return 0;
int h=1,t=1;
qx[1]=sx;qy[1]=sy;
dis[sx][sy]=0;
vis[sx][sy]=tot;
while (h<=t)
int x=qx[h],y=qy[h];h++;
for (int i=1;i<=4;i++)
int xx=x+dx[i];
int yy=y+dy[i];
if (pd(xx,yy)) continue;
if (vis[xx][yy]!=tot)
dis[xx][yy]=dis[x][y]+1;
vis[xx][yy]=tot;
t++;
qx[t]=xx;qy[t]=yy;
if (xx==tx&&yy==ty) return dis[xx][yy];
return 1e7;
void spfa(int s)
memset(dist,53,sizeof dist);
memset(flag,0,sizeof flag);
dist[s]=0;
que[1]=s;
int h=1,t=1;
while (h<=t)
int u=que[h];h++;
flag[u]=0;
for (int p=last[u];p;p=pre[p])
int v=other[p];
if (dist[v]>dist[u]+len[p])
dist[v]=dist[u]+len[p];
if (!flag[v])
que[++t]=v;
flag[v]=1;
int main()
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf("%d",&g[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=4;k++) id[i][j][k]=++cnt;
memset(f,53,sizeof f);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (g[i][j])
for (int k=1;k<=4;k++)
if (pd(i+dx[k],j+dy[k])) continue;
for (int h=1;h<=4;h++)
if (pd(i+dx[h],j+dy[h])) continue;
vis[i][j]=++tot;
f[i][j][k][h]=bfs(i+dx[k],j+dy[k],i+dx[h],j+dy[h])+1;
if (f[i][j][k][h]>1e7-1) continue;
// printf("%d %d %d %d %d\\n",i,j,k,h,f[i][j][k][h]);
connect(id[i][j][k],id[i+dx[h]][j+dy[h]][5-h],f[i][j][k][h]);
while (q--)
int ex,ey,tx,ty,sx,sy;
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if (sx==tx&&sy==ty)
printf("0\\n");
continue;
S=++cnt;T=++cnt;
for (int i=1;i<=4;i++)
vis[sx][sy]=++tot;
if (pd(sx+dx[i],sy+dy[i])) continue;
int temp=bfs(ex,ey,sx+dx[i],sy+dy[i]);
if (temp>1e7-1) continue;
connect(S,id[sx+dx[i]][sy+dy[i]][5-i],temp);
for (int i=1;i<=4;i++)
if (pd(tx+dx[i],ty+dy[i])) continue;
connect(id[tx][ty][i],T,0);
spfa(S);
if (dist[T]>1e7-1) printf("-1\\n");
else printf("%d\\n",dist[T]+1);
return 0;
以上是关于NOIP[2013] 华容道的主要内容,如果未能解决你的问题,请参考以下文章