NOIP[2013] 华容道

来源:互联网 发布:阿里云青岛机房电话 编辑:程序博客网 时间:2024/05/18 03:31

      一道能够让人深刻理解“状态“含义的图论题目。首先一个很简单的做法就是暴力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 1000005int 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;}


0 0
原创粉丝点击