Jzoj P4671 World Tour___bfs+枚举

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/88782081

题目大意:

给出 n n 个点 m m 个单向边,问任选4个点(各不相同)构成的路径A->B->C->D,使得点点间最短路径之和最大时的选点方案是什么。

4 < = n < = 3000 , 3 < = m < = 5000 4<=n<=3000,3<=m<=5000

分析:

所有的边长度均为 1 1 ,那么我们令 d i s i , j dis_{i,j} 表示 i i j j 的最短距离,然后队列中加入 d i s i , i dis_{i,i} ( d i s i , i = 0 dis_{i,i}=0 ),每次往相邻的点跑,先到达的肯定就是最短的。

然后我们对于一个路径 A > B > C > D A->B->C->D ,可以发现 A A 肯定是到 B B 中最大的或者次大的, D D 肯定是 C C 能到中最大的或者次大的,
那么预处理,
a i , 0 / 1 a_{i,0/1} 表示到第 i i 个点最短距离中最大的点和次大的点,
b i , 0 / 1 b_{i,0/1} 表示第 i i 个点能到的其他点的最短距离最大的和次大的是哪个。
然后枚举 B , C B,C A , D A,D 利用预处理的 a , b a,b 去找即可
时间复杂度: O ( n 2 ) O(n^2)

代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
#include <cstring>
#include <algorithm>

#define N 3005
#define M 5005

using namespace std;

struct Node{int To, nxt; }e[M];
int maxFrom[N][2], maxTo[N][2], dis[N][N], ls[N], cnt, n, m;
 
queue <int> Q[2];

void Addedge(int u, int v)
{
    e[++cnt].To = v, e[cnt].nxt = ls[u], ls[u] = cnt; 
}

void spfa()
{
    memset(dis, 255, sizeof(dis));
    for (int i = 1; i <= n; i++)
	    dis[i][i] = 0, Q[0].push(i), Q[1].push(i);
    while (Q[0].size())
	{	
        int now = Q[0].front(); Q[0].pop();
		int u = Q[1].front(); Q[1].pop();
        for (int i = ls[u]; i; i = e[i].nxt)
            if (dis[now][e[i].To] == -1)
			{
                dis[now][e[i].To] = dis[now][u] + 1;
                Q[0].push(now), Q[1].push(e[i].To);
            }
    }
}


bool check(int a, int b, int c, int d)
{
	if (a == b || a == c || a == d || d == b || d == c) return 0;
	return 1; 
}
int main()
{ 
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int u, v; 
		scanf("%d %d", &u, &v);
        Addedge(u, v);
    }
    spfa();
	for (int i = 1; i <= n; i++)
	{
        maxTo[i][1] = maxTo[i][0] = maxFrom[i][1] = maxFrom[i][0] = i;
        for (int j = 1; j <= n; j++)
		{
            if (dis[i][j] > dis[i][maxTo[i][0]]) maxTo[i][1] = maxTo[i][0], maxTo[i][0] = j;
               else if (dis[i][j] > dis[i][maxTo[i][1]]) maxTo[i][1] = j;
               
            if (dis[j][i] > dis[maxFrom[i][0]][i]) maxFrom[i][1] = maxFrom[i][0], maxFrom[i][0] = j;
               else if (dis[j][i] > dis[maxFrom[i][1]][i]) maxFrom[i][1] = j;
        }
    }
    int Answer = -1, A, B, C, D; 
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j && dis[i][j] != -1)
               for (int rk1 = 0; rk1 <= 1; rk1++)
	               for (int rk2 = 0; rk2 <= 1; rk2++)
		           {
                        int begind = maxFrom[i][rk1], endd = maxTo[j][rk2];
                        if (check(begind, i, j, endd) && dis[begind][i] + dis[i][j] + dis[j][endd] > Answer)
						   Answer = dis[begind][i] + dis[i][j] + dis[j][endd], A = begind, B = i, C = j, D = endd;
                           
                   }
    printf("%d %d %d %d\n", A, B, C, D);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Gx_Man_VIP/article/details/88782081
今日推荐