[jzoj 4671] World Tour {bfs+最短路}

题目

Description

Cicasso是一个著名的雕塑家。
现在他想去城市之间旅游,他是一个聪明的人,所以从一个城市到另一个城市他只会走最短路。他想游览全国的风景,所以他想走的路的总长度尽量长,但是经费有限,他只能去四个城市,而且这四个城市不能重复(在途中经过的城市不计算,例如 在这里插入图片描述,他要去的四个城市有上标,[1, 5, 2, 4],这样是合法的)
注意,道路是单向路,并且距离都为1。

Input

在第一行有两个整数n和m(4<=n<=3000,3<=m<=5000),n代表城市数,m代表单向边的数量
接下来m行有两个整数ui,vi(ui,vi<=n)——代表一条从ui到vi的单向边,注意ui和vi可能相同,并且同两个城市之间可能有多条边

Output

输出四个整数,代表Cicasso要旅游的路线。


解题思路

假如四个 不同的城市为 a,b,c,d,对于每一个城市先跑一个 BFS,找出它最短路到达最
远的 3 个点,然后枚举 b,c,然后再枚举 b,c 的这 3 个点,(a,b,c,d 不能相同),找出
最大的即可。


代码80分

#include<cstdio>
#include<string>
#include<cstring>
#include<queue>
#define rr register 
#define rep(i,x,y) for (register int i=x;i<=y;i++)
using namespace std;
const int N=3010,M=5010; 
struct node{int y,z,next;}a[M];
int head[N],n,m,tot,root,d[N],t[N][N]; bool v[N];
int g[N][2][2],a1,a2,a3,a4,ans; 
priority_queue<pair<int,int> >q; 
inline int read()
{
	int p=0; char c=getchar(); 
	while (!isdigit(c)) c=getchar(); 
	while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar(); 
	return p; 
}
void add(int x,int y,int z){a[++tot]=(node){y,z,head[x]}; head[x]=tot;}
void dijkstra(){
	memset(d,0x3f,sizeof(d)); 
	memset(v,0,sizeof(v)); 
	d[root]=0; q.push(make_pair(0,root)); 
	while (q.size()){
		int x=q.top().second; q.pop(); 
		if (v[x]) continue; v[x]=1;
		for (rr int i=head[x];i;i=a[i].next){
			int y=a[i].y,z=a[i].z; 
			if (d[y]>d[x]+z) d[y]=d[x]+z,q.push(make_pair(-d[y],y)); 
		}
	}
}
bool check(int x,int y,int q,int w){if (x==y||x==q||x==w||y==q||y==w||q==w) return 0; return 1; }
int main()
{
	n=read(),m=read();
	for (rr int i=1;i<=m;i++){
	 	 int x=read(),y=read(); 
		 add(x,y,1); 
	} 
	for (root=1;root<=n;root++) {
	   dijkstra(); 
	   rep(i,1,n) t[root][i]=(d[i]!=0x3f3f3f3f)?d[i]:-2147483647; 
	}
	
	rep(i,1,n) rep(j,1,n) {
		if (t[i][j]>t[i][g[i][0][0]]) g[i][1][0]=g[i][0][0],g[i][0][0]=j; 
			 else if (t[i][j]>t[i][g[i][1][0]]) g[i][1][0]=j; 
		if (t[i][j]>t[g[j][0][1]][j]) g[j][1][1]=g[j][0][1],g[j][0][1]=i; 
		     else if (t[i][j]>t[g[j][1][1]][j]) g[j][1][1]=i; 
	}
	 
	rep(i,1,n) rep(j,1,n) if (i!=j)
	if (g[i][0][1]==g[j][0][1]){
		if (t[g[i][1][1]][i]>t[j][g[j][1][0]]) {
		  if (t[g[i][1][1]][i]+t[i][j]+t[j][g[j][0][0]]>ans&&check(g[i][1][1],i,j,g[j][0][0])) {
			  ans=t[g[i][1][1]][i]+t[i][j]+t[j][g[j][0][0]]; 
			  a1=g[i][1][1],a2=i,a3=j,a4=g[j][0][0]; 
		  }
		} else {
		  if (t[g[i][0][1]][i]+t[i][j]+t[j][g[j][1][0]]>ans&&check(g[i][0][1],i,j,g[j][1][0])) {
			  ans=t[g[i][0][0]][i]+t[i][j]+t[j][g[j][1][0]]; 
			  a1=g[i][0][1],a2=i,a3=j,a4=g[j][1][0]; 
		  }	
		}
	} else {
		if (t[g[i][0][1]][i]+t[i][j]+t[j][g[j][0][0]]>ans&&check(g[i][0][1],i,j,g[j][0][0])) {
			  ans=t[g[i][0][1]][i]+t[i][j]+t[j][g[j][0][0]]; 
			  a1=g[i][0][1],a2=i,a3=j,a4=g[j][0][0]; 
		}
	}
	printf("%d %d %d %d",a1,a2,a3,a4); 
}

100分

//以下代码巨丑,请见谅QWQ
#include <queue>
#include <cstdio>
#include <iostream>
#include <cstring>
#define mp make_pair
using namespace std;

const int N=3010;
const int M=5010;
const int Inf=1e9;
int n,m,x,y,tot,ans,a,b,c,d;
int head[N],dis[N][N],maxn[N][3][3],maxx[N][3][3];
bool vis[N];

struct edge
{
	int next,to;
}e[M];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void dij(int S)  //求最短路
{
	memset(vis,0,sizeof(vis));
	priority_queue<pair<int,int> > q;
	q.push(mp(0,S));
	dis[S][S]=0;
	vis[S]=1;
	while (q.size())
	{
		int u=q.top().second;
		q.pop();
		for (int i=head[u];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (dis[S][v]>dis[S][u]+1)
			{
				dis[S][v]=dis[S][u]+1;
				if (!vis[v])
				{
					q.push(mp(-dis[S][v],v));
					vis[v]=1;
				}
			}
		}
	}
}

bool check(int x1,int x2,int x3,int x4)  //判断四个数字是否互不相同
{
	if (x1==x2) return 0;
	if (x1==x3) return 0;
	if (x1==x4) return 0;
	if (x2==x3) return 0;
	if (x2==x4) return 0;
	if (x3==x4) return 0;
	return 1;
}

int main()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
	}
	for (int i=1;i<=n;i++)
		dij(i);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			if (dis[i][j]<Inf)
			{
				if (dis[i][j]>maxn[i][1][1])  //预处理出最长、次长路径
				{
					maxn[i][1][2]=maxn[i][1][1];
					maxx[i][1][2]=maxx[i][1][1];
					maxn[i][1][1]=dis[i][j];
					maxx[i][1][1]=j;
				}
				else if (dis[i][j]>maxn[i][1][2])
				{
					maxn[i][1][2]=dis[i][j];
					maxx[i][1][2]=j;
				}
				if (dis[i][j]>maxn[j][2][1])
				{
					maxn[j][2][2]=maxn[j][2][1];
					maxx[j][2][2]=maxx[j][2][1];
					maxn[j][2][1]=dis[i][j];
					maxx[j][2][1]=i;
				}
				else if (dis[i][j]>maxn[i][2][2])
				{
					maxn[j][2][2]=dis[i][j];
					maxx[j][2][2]=i;
				}
			}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
		{
			if (i==j) continue;
			if (dis[i][j]<Inf&&dis[i][j]+maxn[i][2][1]+maxn[j][1][1]>ans&&check(maxx[i][2][1],maxx[j][1][1],i,j))
			{
				ans=dis[i][j]+maxn[i][2][1]+maxn[j][1][1];
				d=maxx[j][1][1]; c=j;
				b=i; a=maxx[i][2][1];
			}
			if (dis[i][j]<Inf&&dis[i][j]+maxn[i][2][2]+maxn[j][1][1]>ans&&check(maxx[i][2][2],maxx[j][1][1],i,j))
			{
				ans=dis[i][j]+maxn[i][2][2]+maxn[j][1][1];
				d=maxx[j][1][1]; c=j;
				b=i; a=maxx[i][2][2];
			}
			if (dis[i][j]<Inf&&dis[i][j]+maxn[i][2][1]+maxn[j][1][2]>ans&&check(maxx[i][2][1],maxx[j][1][2],i,j))
			{
				ans=dis[i][j]+maxn[i][2][1]+maxn[j][1][2];
				d=maxx[j][1][2]; c=j;
				b=i; a=maxx[i][2][1];
			}
		}
	printf("%d %d %d %d",a,b,c,d);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值