【NOIP2013】华容道 最短路优化搜索(spfa)

华容道

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 34   Solved: 14
[ Submit][ Status][ Web Board]

Description

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

1.       在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1 个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

2.       有些棋子是固定的,有些棋子则是可以移动的;

3.       任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。

游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

      

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX行第 EY列,指定的可移动棋子的初始位置为第 SX行第 SY列,目标位置为第 TX行第 TY列。

 假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请

你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

Input

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

Output

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。

Sample Input

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

Sample Output

2
-1

HINT

【输入输出样例说明】

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

1.第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。

 

2.第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。

【数据范围】

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;

对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;

对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

Source

NOIP2013提高T6


题意:可以想象成首领之傲用R来拉箱子,要把箱子从初始位置拉到指定位置。能则输出最短步数,不能则输出 -1 。

题解:因为只有一个格子是空的,所以我们可以理解为将空白块移动到挨着指定块的位置,然后互换位置,有目的性地重复此操作,直到指定块归位。

首先我们可以想到利用搜索来解题,因为时间复杂度是O(p*n*m*n*m),即4*10^8,所以只好放弃。

这时候我们就想到了A*优化和最短路优化。

(p.s.,要看正解直接“page down”,看到“最短路”再停!)

A* : (不要着急说它是错的,虽然它的确是错的,不乐意看可以直接略过此处到最短路优化一节)很简单,照裸搜来写,然后把估价函数写好就行了。

首先bfs n*m次得出图中任意两点距离dist[][]。然后因为当指定块被空白块转换后,空白块需要至少两步才能到达指定块的另一侧,然后互换位置又是一步,所以我的估价函数写的是dist[a1][b1][x2][y2]*3+dist[a0][b0][a1][b1]即【指定块距离目标位置距离*3+空白块到被移动格子距离*1】。

而状态visit[a][b][c][d]记录的则是指定块在(a,b),空白快在(c,d)时的状态。

代码一60分(visit记录每个状态的最短移动距离)

(由于要省时间,这两个错了算法的代码都是手写堆,pq版删掉了)

#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define N 35
#define NN 1000
using namespace std;
	struct Fiona
	{
		int f,w,x0,y0,x1,y1;
		Fiona(int i1,int i2,int i3,int i4,int i5,int i6)
			:f(i1),w(i2),x0(i3),y0(i4),x1(i5),y1(i6){}
		Fiona(){}
	};
	struct Vayne
	{
		int x,y;
		Vayne(int a,int b):x(a),y(b){}
	};
	int n,m,q,cnt;
	int visit[N][N][N][N],block[N][N];
	int dist[N][N][N][N];
	int direct[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
	int x0,x1,x2;
	int y0,y1,y2;
int eva(int a0,int b0,int a1,int b1)/*估价:空白块和指定块*/
{
	return dist[a1][b1][x2][y2]*2+dist[a0][b0][a1][b1];
}
Fiona heap[NN*NN],c;
void insert(Fiona X)
{
	int t=++cnt;
	for(heap[t]=X;heap[t].f<heap[t>>1].f;t>>=1)c=heap[t],heap[t]=heap[t>>1],heap[t>>1]=c;
}
void pop()
{
	int t=1,son;
	for(heap[t]=heap[cnt--];(t<<1)<=cnt;t=son)
	{
		son=(t<<1==cnt||heap[t<<1].f<heap[t<<1|1].f)?t<<1:t<<1|1;
		if(heap[son].f<heap[t].f)c=heap[t],heap[t]=heap[son],heap[son]=c;
		else break;
	}
}
void priority_bfs()
{
	int i,j,vx,vy,x,y,w,cx,cy;
	scanf("%d%d%d%d%d%d",&x0,&y0,&x1,&y1,&x2,&y2);
	if(x1==x2&&y1==y2)
	{
		printf("0\n");
		return ;
	}
	if(dist[x0][y0][x1][y1]>NN*NN||dist[x1][y1][x2][y2]>NN*NN)
	{
		printf("-1\n");
		return ;
	}
	cnt=0;
	memset(visit,0x11,sizeof(visit));
	Fiona U(eva(x0,y0,x1,y1),0,x0,y0,x1,y1);
	visit[x1][y1][x0][y0]=0;
	insert(U);
	while(cnt)
	{
		U=heap[1];
		pop();
		w=U.w+1;
		x=U.x0;
		y=U.y0;
		cx=U.x1;
		cy=U.y1;
		for(i=0;i<4;i++)
		{
			vx=x+direct[i][0];
			vy=y+direct[i][1];
			if(!block[vx][vy])continue;
			if(vx==cx&&vy==cy)
			{
				if(visit[x][y][cx][cy]>w)
				{
					if(x==x2&&y==y2)
					{
						printf("%d\n",w);
						return ;
					}
					visit[x][y][cx][cy]=w;
					insert(Fiona(eva(cx,cy,x,y)+w,w,cx,cy,x,y));
				}
			}
			else if(visit[cx][cy][vx][vy]>w)
			{
				visit[cx][cy][vx][vy]=w;
				insert(Fiona(eva(vx,vy,cx,cy)+w,w,vx,vy,cx,cy));
			}
		}
	}
	printf("-1\n");
}


void prepare()
{
	int i,j,k,x,y,vx,vy;
	Vayne U(0,0);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			queue<Vayne>q;
			q.push(Vayne(i,j));
			dist[i][j][i][j]=0;
			while(!q.empty())
			{
				U=q.front();
				q.pop();
				x=U.x;
				y=U.y;
				for(k=0;k<4;k++)
				{
					vx=x+direct[k][0];
					vy=y+direct[k][1];
					if(dist[i][j][vx][vy]>1000&&block[vx][vy])
					{
						dist[i][j][vx][vy]=dist[i][j][x][y]+1;
						q.push(Vayne(vx,vy));
					}
				}
			}
		}
	}
}

int main()
{
	freopen("puzzle.in","r",stdin);
	freopen("puzzle.ans","w",stdout);
	memset(dist,0x11,sizeof(dist));
	int i,j;
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)
	{
			scanf("%d",&block[i][j]);
	}
	prepare();
	for(i=1;i<=q;i++)
	{
		priority_bfs();
	}
	return 0;
}
呵呵,20个点只过了前12个,60分。

代码二60分(visit记录是否到过某个状态,这个有明显缺陷,因为有的状态对,即两个状态间可能估价小的实际距离大,所以不能保证第一次搜到某个状态就是最优~)


#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define N 35
#define NN 1000
using namespace std;
	struct Fiona
	{
		int f,w,x0,y0,x1,y1;
		Fiona(int i1,int i2,int i3,int i4,int i5,int i6)
			:f(i1),w(i2),x0(i3),y0(i4),x1(i5),y1(i6){}
		Fiona(){}
	};
	struct Vayne
	{
		int x,y;
		Vayne(int a,int b):x(a),y(b){}
	};
	int n,m,q,cnt;
	int visit[N][N][N][N],block[N][N];
	int dist[N][N][N][N];
	int direct[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
	int x0,x1,x2;
	int y0,y1,y2;
int eva(int a0,int b0,int a1,int b1)/*估价:空白格和被动格*/
{
	return dist[a1][b1][x2][y2]*3+dist[a0][b0][a1][b1];
}
Fiona heap[NN*NN],c;
void insert(Fiona X)
{
	int t=++cnt;
	for(heap[t]=X;heap[t].f<heap[t>>1].f;t>>=1)c=heap[t],heap[t]=heap[t>>1],heap[t>>1]=c;
}
void pop()
{
	int t=1,son;
	for(heap[t]=heap[cnt--];(t<<1)<=cnt;t=son)
	{
		son=(t<<1==cnt||heap[t<<1].f<heap[t<<1|1].f)?t<<1:t<<1|1;
		if(heap[son].f<heap[t].f)c=heap[t],heap[t]=heap[son],heap[son]=c;
		else break;
	}
}
void priority_bfs(int cases)
{
	int i,vx,vy,x,y,w,cx,cy;
	scanf("%d%d%d%d%d%d",&x0,&y0,&x1,&y1,&x2,&y2);
	if(x1==x2&&y1==y2)
	{
		printf("0\n");
		return ;
	}
	if(dist[x0][y0][x1][y1]>NN*NN||dist[x1][y1][x2][y2]>NN*NN)
	{
		printf("-1\n");
		return ;
	}
	cnt=0;
	Fiona U(eva(x0,y0,x1,y1),0,x0,y0,x1,y1);
	visit[x1][y1][x0][y0]=cases;
	insert(U);
	while(cnt)
	{
		U=heap[1];
		pop();
		w=U.w+1;
		x=U.x0;
		y=U.y0;
		cx=U.x1;
		cy=U.y1;
		for(i=0;i<4;i++)
		{
			vx=x+direct[i][0];
			vy=y+direct[i][1];
			if(!block[vx][vy])continue;
			if(vx==cx&&vy==cy)
			{
				if(visit[x][y][cx][cy]!=cases)
				{
					if(x==x2&&y==y2)
					{
						printf("%d\n",w);
						return ;
					}
					visit[x][y][cx][cy]=cases;
					insert(Fiona(eva(cx,cy,x,y)+w,w,cx,cy,x,y));
				}
			}
			else if(visit[cx][cy][vx][vy]!=cases)
			{
				visit[cx][cy][vx][vy]=cases;
				insert(Fiona(eva(vx,vy,cx,cy)+w,w,vx,vy,cx,cy));
			}
		}
	}
	printf("-1\n");
}


void prepare()
{
	int i,j,k,x,y,vx,vy;
	Vayne U(0,0);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			queue<Vayne>q;
			q.push(Vayne(i,j));
			dist[i][j][i][j]=0;
			while(!q.empty())
			{
				U=q.front();
				q.pop();
				x=U.x;
				y=U.y;
				for(k=0;k<4;k++)
				{
					vx=x+direct[k][0];
					vy=y+direct[k][1];
					if(dist[i][j][vx][vy]>1000&&block[vx][vy])
					{
						dist[i][j][vx][vy]=dist[i][j][x][y]+1;
						q.push(Vayne(vx,vy));
					}
				}
			}
		}
	}
}

int main()
{
	freopen("puzzle.in","r",stdin);
	freopen("puzzle.ans","w",stdout);
	memset(dist,0x11,sizeof(dist));
	int i,j;
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)
	{
			scanf("%d",&block[i][j]);
	}
	prepare();
	for(i=1;i<=q;i++)
	{
		priority_bfs(i);
	}
	return 0;
}
这个更呵呵了,同样过了前12个点,60分,但是还有WA的。

打击人的是代码三70分(不要A*的裸搜,同学写的):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
using namespace std;
struct state
{
    int space_x,space_y,son_x,son_y,step;
    state(){space_x=space_y=son_x=son_y=step=0;}
};
bool hash[31][31][31][31];
int map[101][101];
int main()
{
    freopen("puzzle.in","r",stdin);
    freopen("puzzle.ans","w",stdout);
    register int i,j;
    int n,m,t;
    scanf("%d%d%d",&n,&m,&t);
    for(i=1;i<=n;++i)
    for(j=1;j<=m;++j)
        scanf("%d",&map[i][j]);
    queue<state> q;
    while(t--)
    {
        memset(hash , 0 , sizeof(hash));
        int s_x,s_y,b_x,b_y,e_x,e_y;
        scanf("%d%d%d%d%d%d",&s_x,&s_y,&b_x,&b_y,&e_x,&e_y);
        hash[s_x][s_y][b_x][b_y] = 1;
        state begin;
        begin.space_x=s_x;
        begin.space_y=s_y;
        begin.son_x=b_x;
        begin.son_y=b_y;
        begin.step=0;
        q.push(begin);
        bool find=0;
        while(!q.empty())
        {
            state ins=q.front();
            q.pop();
            if(ins.son_x==e_x&&ins.son_y==e_y)
            {
                printf("%d\n",ins.step);
                find=1;
                break;
            }
            for(i=0;i<4;++i)
            {
                int tx=ins.space_x+dx[i];
                int ty=ins.space_y+dy[i];
                if((tx!=ins.son_x||ty!=ins.son_y)&&tx>=1&&tx<=n&&ty>=1&&ty<=m)
                {
                    if((tx!=ins.son_x||ty!=ins.son_y)&&map[tx][ty])
                    if(!hash[tx][ty][ins.son_x][ins.son_y])
                    {
                        hash[tx][ty][ins.son_x][ins.son_y] = 1;
                        state tmp;
                        tmp.space_x=tx;
                        tmp.space_y=ty;
                        tmp.son_x=ins.son_x;
                        tmp.son_y=ins.son_y;
                        tmp.step=ins.step+1;
                        q.push(tmp);
                    }
                }
            }
            if(abs(ins.space_x-ins.son_x)+abs(ins.space_y-ins.son_y)==1)
            {
                int tx=ins.space_x;
                int ty=ins.space_y;
                if(!hash[ins.son_x][ins.son_y][tx][ty])
                {
                    hash[ins.son_x][ins.son_y][tx][ty] = 1;
                    state tmp;
                    tmp.space_x=ins.son_x;
                    tmp.space_y=ins.son_y;
                    tmp.son_x=tx;
                    tmp.son_y=ty;
                    tmp.step=ins.step+1;
                    q.push(tmp);
                }
            }
        }
        if(!find) printf("-1\n");
        q = queue<state>();
    }
    return 0;    
}
这个代码70分,分析一下,是因为A*有个log级别维护最值的常数,所以反而慢了些(不要着急反驳说还有更多的原因)

真正让我放弃A*的是当我把估价函数写成return 0时,代码竟然变快了?!!于是我就开始认真分析A*的优劣了。


总结:A*适合冗余状态较多(,估价函数好写)的搜索,这样可以删减去很多没用的搜索(搜索方向),这一切,盖因它是一种有目的性,或者说有方向性的搜索,而估价函数赋予了它这种方向性。同时有一个小总结就是,A*需要:在最优路径上,每个状态的估价函数值需要保持非严格递增(当然严格更好),否则若在最优路径上估价函数值是波动的,则可能走错方向,导致反而增添了许多冗余的搜索!于是,这题还写搜索?还写A*?还写双向BFS?见鬼去吧,最短路才可以拯救你。


最短路这道题的图其实是一张n*m的图,动态加障碍(指定块),然后bfs搜索转移状态,所以我们完全可以预处理一遍,加边,然后跑最短路。

那么该如何加边呢?

啊,很简单,不要想太难。两个比较有用的状态之间加容易加的边就好了。什么叫有用的状态呢?就是一个“空白块挨着指定块”状态!

此题加的边为一个 “有用状态” 到一个指定块与其相邻的 “有用状态” ,然后每次询问连源连汇,万事大吉。

附代码,不懂自己看,或者手调,不是很难理解。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 35
#define NN 7000
#define M 25000
#define inf 0x3f3f3f3f
using namespace std;
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct Syndra
{
	int u,v,len,next;
}e[M];
struct Fiona
{
	int x,y;
	Fiona(int a,int b):x(a),y(b){}
	Fiona(){}
};
struct Vayne
{
	int f,v;
	Vayne(int a,int b):f(a),v(b){}
	Vayne(){}
	bool operator < (const Vayne& a)const
	{return a.f<f;}
};
int head[NN],id[N][N][N],cnt,num;
int map[N][N];
int n,m,query;
queue<Fiona>q;
queue<int>Q;
priority_queue<Vayne> pq;
int dis[N][N],dist[NN],in[NN];
void add(int u,int v,int len)
{
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int bfs(int sx,int sy,int tx,int ty)/*已检查,绝对正确*/
{
	int i,vx,vy;
	if(sx==tx&&sy==ty)return 0;
	if(!map[sx][sy]||!map[tx][ty])return inf;
	while(!q.empty())q.pop();
	memset(dis,0x3f,sizeof(dis));
	q.push(Fiona(sx,sy));
	dis[sx][sy]=0;
	while(!q.empty())
	{
		Fiona U=q.front();
		q.pop();
		for(i=0;i<4;i++)
		{
			vx=U.x+dir[i][0];
			vy=U.y+dir[i][1];
			if(dis[vx][vy]>dis[U.x][U.y]+1&&map[vx][vy])
			{
				dis[vx][vy]=dis[U.x][U.y]+1;
				if(vx==tx&&vy==ty)return dis[vx][vy];
				q.push(Fiona(vx,vy));
			}
		}
	}
	return inf;
}

int pqspfa(int s,int t)
{
	int i,u,v;
	Vayne X;
	memset(dist,0x3f,sizeof(dist));
	memset(in,0,sizeof(in));
	while(!pq.empty())pq.pop();
	pq.push(Vayne(0,s));
	dist[s]=0;
	in[s]=1;
	while(!pq.empty())
	{
		X=pq.top();
		pq.pop();
		u=X.v;
		in[u]=0;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(dist[v]>dist[u]+e[i].len)
			{
				dist[v]=dist[u]+e[i].len;
				if(!in[v])pq.push(Vayne(dist[v],v)),in[v]=1;
			}
		}
	}
	return dist[t]<inf?dist[t]:-1;
}

int spfa(int s,int t)/*已检查,绝对正确*/
{
	int i,u,v;
	memset(dist,0x3f,sizeof(dist));
	memset(in,0,sizeof(in));
	while(!Q.empty())Q.pop();
	Q.push(s);
	dist[s]=0;
	in[s]=1;
	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();
		in[u]=0;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(dist[v]>dist[u]+e[i].len)
			{
				dist[v]=dist[u]+e[i].len;
				if(!in[v])Q.push(v),in[v]=1;
			}
		}
	}
	return dist[t]<inf?dist[t]:-1;
}
void build()/*已检查,绝对正确*/
{
	int i,j,k,l,i1,j1,i2,j2;
	int temp;
	scanf("%d%d%d",&n,&m,&query);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			scanf("%d",&map[i][j]);
			for(k=0;k<4;k++)id[i][j][k]=++num;
		}
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)if(map[i][j])
		{
			map[i][j]=0;
			for(k=0;k<4;k++)if(map[i1=i+dir[k][0]][j1=j+dir[k][1]])
			{
				for(l=k;l<4;l++)if(map[i2=i+dir[l][0]][j2=j+dir[l][1]])
				{
					temp=bfs(i1,j1,i2,j2)+1;
					if(temp<inf)
					{
						add(id[i][j][k],id[i2][j2][l^1],temp);
						if(k!=l)add(id[i][j][l],id[i1][j1][k^1],temp);
					}
				}
			}
			map[i][j]=1;
		}
	}
	/*上为优化,下为标程*/
/*
	int move[N][N][N][N];
	memset(move,0x3f,sizeof(move));
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)if(map[i][j])
		{
			map[i][j]=0;
			for(k=0;k<4;k++)if(map[i1=i+dir[k][0]][j1=j+dir[k][1]])
			{
				for(l=0;l<4;l++)if(map[i2=i+dir[l][0]][j2=j+dir[l][1]])
				{
					move[i][j][k][l]=bfs(i1,j1,i2,j2)+1;
				}
			}
			map[i][j]=1;
		}
	}
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)
	{
		for(k=0;k<4;k++)for(l=0;l<4;l++)
		{
			if(move[i][j][k][l]<inf)add(id[i][j][k],id[i+dir[l][0]][j+dir[l][1]][l^1],move[i][j][k][l]);
		}
	}
*/
}
void handle()/*已检查:绝对正确*/
{
	int i,s,t;
	int vx,vy,temp;
	int bx,by,sx,sy,tx,ty;
	while(query--)
	{
		scanf("%d%d%d%d%d%d",&bx,&by,&sx,&sy,&tx,&ty);
		if(sx==tx&&sy==ty)
		{
			printf("0\n");
			continue;
		}
		if(!map[sx][sy]||!map[tx][ty])
		{
			printf("-1\n");
			continue;
		}
		s=++num;
		t=++num;
		
		map[sx][sy]=0;
		for(i=0;i<4;i++)
		{
			vx=sx+dir[i][0];
			vy=sy+dir[i][1];
			if(!map[vx][vy])continue;
			temp=bfs(bx,by,vx,vy);
			if(temp<inf)add(s,id[sx][sy][i],temp);
		}
		map[sx][sy]=1;
		for(i=0;i<4;i++)if(map[tx+dir[i][0]][ty+dir[i][1]])add(id[tx][ty][i],t,0);
		printf("%d\n",spfa(s,t));
	}
}
int main()/*这里不需要检查*/
{
	freopen("puzzle.in","r",stdin);
	freopen("puzzle.ans","w",stdout);
	build();
	handle();
	return 0;
}


另:这道题略坑,“卡优化”,上面代码spfa 0.84秒20组数据完成,pqspfa?1.6s+!



这里还有一个删节版,就是把没用的都删掉了

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 35
#define NN 7000
#define M 25000
#define inf 0x3f3f3f3f
using namespace std;
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct Syndra
{
	int u,v,len,next;
}e[M];
struct Fiona
{
	int x,y;
	Fiona(int a,int b):x(a),y(b){}
	Fiona(){}
};
int head[NN],id[N][N][N],cnt,num;
int map[N][N];
int n,m,query;
queue<Fiona>q;
queue<int>Q;
int dis[N][N],dist[NN],in[NN];
void add(int u,int v,int len)
{
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int bfs(int sx,int sy,int tx,int ty)
{
	int i,vx,vy;
	if(sx==tx&&sy==ty)return 0;
	if(!map[sx][sy]||!map[tx][ty])return inf;
	while(!q.empty())q.pop();
	memset(dis,0x3f,sizeof(dis));
	q.push(Fiona(sx,sy));
	dis[sx][sy]=0;
	while(!q.empty())
	{
		Fiona U=q.front();
		q.pop();
		for(i=0;i<4;i++)
		{
			vx=U.x+dir[i][0];
			vy=U.y+dir[i][1];
			if(dis[vx][vy]>dis[U.x][U.y]+1&&map[vx][vy])
			{
				dis[vx][vy]=dis[U.x][U.y]+1;
				if(vx==tx&&vy==ty)return dis[vx][vy];
				q.push(Fiona(vx,vy));
			}
		}
	}
	return inf;
}

int spfa(int s,int t)
{
	int i,u,v;
	memset(dist,0x3f,sizeof(dist));
	memset(in,0,sizeof(in));
	while(!Q.empty())Q.pop();
	Q.push(s);
	dist[s]=0;
	in[s]=1;
	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();
		in[u]=0;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(dist[v]>dist[u]+e[i].len)
			{
				dist[v]=dist[u]+e[i].len;
				if(!in[v])Q.push(v),in[v]=1;
			}
		}
	}
	return dist[t]<inf?dist[t]:-1;
}
void build()
{
	int i,j,k,l,i1,j1,i2,j2;
	int temp;
	scanf("%d%d%d",&n,&m,&query);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			scanf("%d",&map[i][j]);
			for(k=0;k<4;k++)id[i][j][k]=++num;
		}
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)if(map[i][j])
		{
			map[i][j]=0;
			for(k=0;k<4;k++)if(map[i1=i+dir[k][0]][j1=j+dir[k][1]])
			{
				for(l=k;l<4;l++)if(map[i2=i+dir[l][0]][j2=j+dir[l][1]])
				{
					temp=bfs(i1,j1,i2,j2)+1;
					if(temp<inf)
					{
						add(id[i][j][k],id[i2][j2][l^1],temp);
						if(k!=l)add(id[i][j][l],id[i1][j1][k^1],temp);
					}
				}
			}
			map[i][j]=1;
		}
	}
}
void handle()
{
	int i,s,t;
	int vx,vy,temp;
	int bx,by,sx,sy,tx,ty;
	while(query--)
	{
		scanf("%d%d%d%d%d%d",&bx,&by,&sx,&sy,&tx,&ty);
		if(sx==tx&&sy==ty)
		{
			printf("0\n");
			continue;
		}
		if(!map[sx][sy]||!map[tx][ty])
		{
			printf("-1\n");
			continue;
		}
		s=++num;
		t=++num;
		
		map[sx][sy]=0;
		for(i=0;i<4;i++)
		{
			vx=sx+dir[i][0];
			vy=sy+dir[i][1];
			if(!map[vx][vy])continue;
			temp=bfs(bx,by,vx,vy);
			if(temp<inf)add(s,id[sx][sy][i],temp);
		}
		map[sx][sy]=1;
		for(i=0;i<4;i++)if(map[tx+dir[i][0]][ty+dir[i][1]])add(id[tx][ty][i],t,0);
		printf("%d\n",spfa(s,t));
	}
}
int main()
{
	build();
	handle();
	return 0;
}


你可能感兴趣的:(搜索,SPFA,a,华容道,NOIp2013)