noip2013day2T3华容道

这道题,写的很醉啊。。。。

这种搜索的题,还带一点DP,各种bug调了好久,

思路:

60分做法就直接bfs乱搞,60分到手;

ac套路:

首先预处理出f[i][j][k]状态,对于点ij,空格在k方向就是开个【30】【30】【4】的数组,再用邻接表存下来,spfa跑一边最短路就好了,注意终点和起点是可能重合的;

code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
const int N=35;
const int M=400010;
const int inf=1000000000;
using namespace std;
bool vis[N][N];
const int d[4][2]={{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
struct point{
	int x, y, d;
};
int n,m,q,map[N][N];
int bfs(int x1, int y1, int x2, int y2){
	for(int i=1; i<=n; ++i)
		for(int j=1; j<=m; ++j)vis[i][j]=false;
	vis[x1][y1]=true;
	queue<point>q;
	q.push((point){x1, y1, 0});
	while(!q.empty()){
		int x=q.front().x,y=q.front().y,dd=q.front().d;
		if(x==x2 && y==y2)return dd;
		q.pop();
		for(int i=0;i<=3;++i){
			int u=x+d[i][0];
			int v=y+d[i][1];
			if(map[u][v] && !vis[u][v]){
				vis[u][v]=1;
				q.push((point){u,v,dd+1});
			}
		}
	}
	return inf;
}
int start[M],nxt[M],to[M],w[M],e;  
void add(int x, int y, int z){
	to[++e]=y;
	nxt[e]=start[x];
	start[x]=e;
	w[e]=z;
}
int f[N][N][4],cnt;
void pre(){
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			for(int k=0;k<=3;++k)
				f[i][j][k]=++cnt;
	int t;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j){
			if(map[i][j])map[i][j]=0;else continue;
			for(int k=0;k<=3;++k)
				for(int l=0;l<=3;++l){
					int x1=i+d[k][0],y1=j+d[k][1],x2=i+d[l][0],y2=j+d[l][1];
					if(map[x1][y1] && map[x2][y2]){
						t=bfs(x1,y1,x2,y2);
						if(t<inf)add(f[i][j][k],f[x2][y2][l^1],t+1);
					}
				}
			map[i][j]=1;
		}
}
int p[M],dis[M];
int spfa(int s,int t){
	queue<int>q;
	for(int i=1;i<=cnt;++i)dis[i]=inf,p[i]=0;
	p[s]=1;
	q.push(s);
	dis[s]=0;
	while(!q.empty()){
		int u=q.front();
		p[u]=0;
		q.pop();
		for(int i=start[u];i;i=nxt[i]){
			int v=to[i];
			if(dis[v]>dis[u]+w[i]){
				dis[v]=dis[u]+w[i];
				if(!p[v])q.push(v);
				p[v]=1;
			}
		}
	}
	return dis[t]<inf?dis[t]:-1;
}
int main(){
	int x,y,x1,y1,x2,y2,t;
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&map[i][j]);
	pre();
	for(int i=1;i<=q;++i){
		int S=++cnt,T=++cnt;
		scanf("%d%d%d%d%d%d",&x,&y,&x1,&y1,&x2,&y2);
		if(x1==x2 && y1==y2){
			puts("0");continue;
		}
		if(!map[x1][y1] || !map[x2][y2]){
            puts("-1");
            continue;
        }
        map[x1][y1]=0;
//搜索出空格的移动状态
       for(int j=0;j<=3;++j){
            int u=x1+d[j][0],v=y1+d[j][1];
            if(map[u][v]){
                int t=bfs(x, y, u, v);
                if(t < inf)add(S, f[x1][y1][j], t);
            }
        }
		map[x1][y1]=1;
        for(int j=0;j<=3;++j){
            int u=x2+d[j][0],v=y2+d[j][1];
            if(map[u][v])add(f[x2][y2][j], T, 0);
        }
		printf("%d\n",spfa(S,T));
	}
}


posted @ 2016-07-09 09:44  pbvrvnq  阅读(104)  评论(0编辑  收藏  举报