四点旅行——枚举的妙用

四点旅行

简要题意

给定 一个\(n\)个点,\(m\)条边的有向图,边的长度都是1。
\(dis(x,y)\)\(x\)\(y\)的最短路径。

求四个不同的点\(a,b,c,d\),满足\(dis(a,b)+dis(b,c)+dis(c,d)\)最大。
输出最大距离。

解法

这题的思路比较显然,也比较巧妙
首先,观察到共有4个点,在加上数据范围较小,这样的题目肯定是需要我们枚举
那么考虑枚举什么比较好算。
由于题目本质是要找到最长的三条相接的链,那么确定了每条链的端点就可以确定路径了

看到点只有2000,可以想到枚举2个点再去找剩下的两个点。
这时候,枚举就应该枚举信息尽可能多的点。
显然中间的枚举两个点b,c最好,因为在枚举的同时就已经确定了一条链,剩下的只需要分别找到两个点合法的最远点

现在问题来到如何迅速找到任意一点的合法最远点
再回看2000的范围,显然我们可以用一个dis[][]数组存储点对间的距离。
因此我只需要O(n^2)的预处理即可找到最远点。
至于合法性判定,只要最远点不是已经选到的点即可。
由于只有四个点,因此每个点选出的最远点最多冲突两次,那么只需要在预处理时存储下每个点的前三远点即可,问题解决。

Coding:

#pragma GCC optimize("O2")
#include<bits/stdc++.h>
#define N 5005
#define max(a,b) a>b? a:b
using namespace std;
template <typename T>
void read(T &x){
	int w=1;x=0;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
	x*=w;
}
int n,m,tot,ans;
int head[N],nex[N],to[N],dis[N][N],mx1[N][5],mx2[N][5];
queue<int>q;
void add(int x,int y){
	to[++tot]=y;
	nex[tot]=head[x];
	head[x]=tot;
}
void bfs(int s){
	int x,y;
	for(int i=1;i<=n;i++)dis[s][i]=-1;
	dis[s][s]=0;
	q.push(s);
	while(!q.empty()){
		x=q.front();
		q.pop();
		for(int i=head[x];i;i=nex[i]){
			int v=to[i];
			if(dis[s][v]!=-1)continue;
			dis[s][v]=dis[s][x]+1;
			q.push(v);
		}
	}
	for(int i=1;i<=n;i++){
		if(dis[s][i]==-1)continue;
		int &a=mx1[s][1],&b=mx1[s][2],&c=mx1[s][3];
		if(dis[s][i]>dis[s][a])c=b,b=a,a=i;
		else if(dis[s][i]>dis[s][b])c=b,b=i;
		else if(dis[s][i]>dis[s][c])c=i;
	}
	for(int i=1;i<=n;i++){
		if(dis[s][i]==-1)continue;
		int &a=mx2[i][1],&b=mx2[i][2],&c=mx2[i][3];
		if(dis[s][i]>dis[a][i])c=b,b=a,a=s;
		else if(dis[s][i]>dis[b][i])c=b,b=s;
		else if(dis[s][i]>dis[c][i])c=s;
	}
}
signed main(){
	int u,v,a,d;
	read(n),read(m);
	for(int i=1;i<=m;i++){
		read(u),read(v);
		add(u,v);
	}	
	for(int i=1;i<=n;i++)bfs(i);
	for(int b=1;b<=n;b++)for(int c=1;c<=n;c++){
		if(b==c||dis[b][c]==-1)continue;
		for(int i=1;i<=3;i++)for(int j=1;j<=3;j++){
			a=mx2[b][i],d=mx1[c][j];
			if(a==d||a==b||a==c||d==c||d==b||a==0||d==0)continue;
			ans=max(ans,dis[a][b]+dis[b][c]+dis[c][d]);
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-10-30 22:23  windf_风岚  阅读(49)  评论(0)    收藏  举报
1