双向宽搜

从起点和终点两个方向交替扩展
两端节点较少的一端先扩展
例题 Knight Moves
本题棋盘太大单项宽搜的话肯定会超时,所以用双向的
代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,l,x1,y1,x2,y2,q[2][2][100001],h[2],t[2],ans;
int d[2][301][301];
int mb[8][2]={{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1}};
bool f[2][301][301];
void lzr()
{
	memset(q,0,sizeof(q));
	memset(d,0,sizeof(d));
	for(int i=1;i<=l;i++) for(int j=1;j<=l;j++) f[0][i][j]=f[1][i][j]=0;
	h[0]=h[1]=1;t[0]=t[1]=1;
	q[0][0][1]=x1;q[0][1][1]=y1;
	q[1][0][1]=x2;q[1][1][1]=y2;
	f[0][x1][y1]=f[1][x2][y2]=1;
	while(h[0]<=t[0]&&h[1]<=t[1]){
		if(t[0]-h[0]<t[1]-h[1]){		
			for(int i=0;i<8;i++){
				int x=q[0][0][h[0]]+mb[i][0],y=q[0][1][h[0]]+mb[i][1];
				if(!f[0][x][y]&&x>=1&&y>=1&&x<=l&&y<=l){
					t[0]++;
					q[0][0][t[0]]=x;q[0][1][t[0]]=y;
					f[0][x][y]=1;
					d[0][x][y]=d[0][q[0][0][h[0]]][q[0][1][h[0]]]+1;
					if(f[1][x][y]){
						ans=d[0][x][y]+d[1][x][y];
						return;
					}
				}
			}
			h[0]++;
		}
		else {
			for(int i=0;i<8;i++){
				int x=q[1][0][h[1]]+mb[i][0],y=q[1][1][h[1]]+mb[i][1];
				if(!f[1][x][y]&&x>=1&&y>=1&&x<=l&&y<=l){
					t[1]++;
					q[1][0][t[1]]=x;q[1][1][t[1]]=y;
					f[1][x][y]=1;
					d[1][x][y]=d[1][q[1][0][h[1]]][q[1][1][h[1]]]+1;
					if(f[0][x][y]){
						ans=d[0][x][y]+d[1][x][y];
						return;
					}
				}
			}
			h[1]++;
		}
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&l);
		scanf("%d%d",&x1,&y1);
		scanf("%d%d",&x2,&y2);
		if(x1==x2&&y1==y2) cout<<"0\n";
		else {lzr();cout<<ans<<endl;}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42920137/article/details/88647238
今日推荐