Codeforces 666 B. World Tour
http://codeforces.com/problemset/problem/666/B
题意:
给定一张边权均为1的有向图,求四个不同的点A,B,C,D,使得dis[A][B]+dis[B][C]+dis[C][D]尽可能大。
预处理能到B的前3远,C能到的前3远
枚举B、C
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define N 3001 #define M 5001 int n; int tot,front[N],to[M],nxt[M]; int dis[N][N],f[N][3],g[N][3]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; } void bfs(int s) { int now,t; static queue<int>q; q.push(s); while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) { t=to[i]; if(dis[s][t]==-1) { dis[s][t]=dis[s][now]+1; q.push(t); } } } } void solve() { int a,b,c,d; int len=0; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j && dis[i][j]!=-1) for(int k=2;k>=0;--k) for(int l=2;l>=0;--l) if(f[i][k]!=i && f[i][k]!=j && g[j][l]!=i && g[j][l]!=j && f[i][k]!=g[j][l]) if(dis[i][j]+dis[f[i][k]][i]+dis[j][g[j][l]]>len) { len=dis[i][j]+dis[f[i][k]][i]+dis[j][g[j][l]]; a=f[i][k]; b=i; c=j; d=g[j][l]; } printf("%d %d %d %d",a,b,c,d); } void pre() { for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { if(dis[i][j]>dis[i][g[i][0]]) { g[i][2]=g[i][1]; g[i][1]=g[i][0]; g[i][0]=j; } else if(dis[i][j]>dis[i][g[i][1]]) { g[i][2]=g[i][1]; g[i][1]=j; } else if(dis[i][j]>dis[i][g[i][2]]) g[i][2]=j; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { if(dis[j][i]>dis[f[i][0]][i]) { f[i][2]=f[i][1]; f[i][1]=f[i][0]; f[i][0]=j; } else if(dis[j][i]>dis[f[i][1]][i]) { f[i][2]=f[i][1]; f[i][1]=j; } else if(dis[j][i]>dis[f[i][2]][i]) f[i][2]=j; } } int main() { int m; read(n); read(m); int u,v; while(m--) { read(u); read(v); add(u,v); } memset(dis,-1,sizeof(dis)); for(int i=1;i<=n;++i) dis[i][i]=0; for(int i=1;i<=n;++i) bfs(i); pre(); solve(); }