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] 华容道的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2013华容道

NOIP2013 华容道

[NOIP2013]华容道

CodeVS 3290NOIP 2013华容道

NOIP2013 华容道

[RT][NOIP2013]华容道