【BFS】lydsy3161 孤舟蓑笠翁

a
b
c

 题目描述很详细了,不多说了。
 今天因为很粗心的bug肝到了这么晚,真的惨。
 这道题一开始想知道是状态当点,也知道是广搜,但是显然直接广搜会T。想不出来,忍不住查阅了一下题解(天哪我怎么这么菜),发现其实就是把所有绝招状态点都塞入队列一起广搜,然后记录每个绝招状态点的邻域(指的是某个区域,区域中点离该绝招状态点最近),这样的话,跨过邻域的边就可以用来更新答案了,也就是说两个绝招状态之间的距离一定是经过这些跨过邻域的边的,所有相邻绝招状态的距离最小值就是我们要的答案了。这个其实有点像“双向广搜”,两头一起搜找到对接点,或者可以起个名字叫“多向广搜”了,其实这个技巧以前用过不少,现在居然生疏了。
 这么做的效率是多少呢?扩展过程中,假设当前状态点为(f1,f2)那么与其有相连边的就是所有(f3,f4)其中点f3与f1相连,点f4与f2相连(在题目中边的意义下)。总状态nn,边一共mm级别,广搜过程中每条边只访问两遍,所以总效率是mm+nn级别的。
 现在自己的水平,离明年拿金牌还很远,需要加强训练呀! 加油 Max,加油Alchemist!

#include<cstdio>
#include<vector>
#include<algorithm>
#define x first
#define y second
using namespace std;

int n,m,k,dmin,dmax,zone[1005][1005],stp[1005][1005],ans[1000005];
pair<int,int> Q[1000005],p[1005];
vector<int> L[1005],R[1005];
int h,t;

inline void expand(int ox, int oy, int nx, int ny)
{
	int tmp=abs(p[nx].x-p[ny].x)+abs(p[nx].y-p[ny].y);
	if(tmp<dmin||tmp>dmax)
		return ;
	if(!zone[nx][ny])
	{
		Q[t++]=pair<int,int>{nx,ny};
		zone[nx][ny]=zone[ox][oy];
		stp[nx][ny]=stp[ox][oy]+1;
	}
	else if(zone[nx][ny]!=zone[ox][oy])
	{
		ans[zone[nx][ny]]=min(ans[zone[nx][ny]],stp[ox][oy]+stp[nx][ny]+1);
		ans[zone[ox][oy]]=min(ans[zone[ox][oy]],stp[ox][oy]+stp[nx][ny]+1);
	}
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&dmin,&dmax);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&p[i].x,&p[i].y);
		L[i].push_back(i);
		R[i].push_back(i);
	}
	scanf("%d",&k);
	for(int i=1,v,u;i<=k;i++)
	{
		scanf("%d%d",&v,&u);
		Q[t++]=pair<int,int>{v,u};
		zone[v][u]=i;
	}
	for(int i=1,tx,ty,o;i<=m;i++)
	{
		scanf("%d%d%d",&tx,&ty,&o);
		if(o)
			R[tx].push_back(ty),R[ty].push_back(tx);
		else
			L[tx].push_back(ty),L[ty].push_back(tx);
	}
	for(int i=1;i<=k;i++)
		ans[i]=1E9;
	while(h<t)
	{
		for(int i=0;i<L[Q[h].x].size();i++)
			for(int j=0;j<R[Q[h].y].size();j++)
				expand(Q[h].x,Q[h].y,L[Q[h].x][i],R[Q[h].y][j]);
		h++;
	}
	for(int i=1;i<=k;i++)
		printf("%d\n",ans[i]==1E9?-1:ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/BUAA_Alchemist/article/details/84889294
BFS