luogu P4408 [NOI2003]逃学的小孩(树的直径)

整理的算法模板合集: ACM模板


luogu P4408 [NOI2003]逃学的小孩(树的直径)_第1张图片
看了半天的题原来没有告诉你三个点的坐标,不然直接跑最短路即可。要求最长的时间,所以我们要自己找到三个点,而在树中最长的路径也就是树的直径。那么本题就可以简化为:在一棵无根树上,找 A , B , C A,B,C A,B,C三个点,使得 A B + B C ( A C > B C ) AB+BC(AC>BC) AB+BC(AC>BC) A C + A B ( B C > A C ) AC+AB(BC>AC) AC+AB(BC>AC)最大。

我们假设 A C > B C AC>BC AC>BC,那么答案就是找到最大 A B + B C AB+BC AB+BC简单贪心一下,先令AB最大,然后再找一个相应的最大的BC,强调要满足(AC>AB)所以我们首先找出树的直径,然后枚举除了两个端点外的点 C C C,使得 m i n ( A C , B C ) min(AC,BC) min(AC,BC)最大,答案就是树的直径 + m i n ( A C , B C ) +min(AC,BC) +min(AC,BC)

#include
#include
#include
#include
#include

using namespace std;
typedef long long ll;
const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

int n, m;
ll d[N], copy_d[N];
bool vis[N];
int head[N], ver[M], nex[M], edge[M], tot;

void add(int x, int y, int z)
{
     
    ver[tot] = y;
    edge[tot] = z;
    nex[tot] = head[x];
    head[x] = tot ++ ;
}

int bfs(int S)
{
     
    queue<int>q;
    memset(d, 0, sizeof d);
    memset(vis, 0, sizeof vis);
    //while(q.size())q.pop();
    q.push(S), vis[S] = 1;

    int maxx = 0, maxid;
    while(q.size()){
     
        int x = q.front();
        q.pop();
        for(int i = head[x]; ~i; i = nex[i]){
     
            int y = ver[i], z = edge[i];
            if(vis[y])continue;
            vis[y] = 1;
            d[y] = d[x] + z;
            q.push(y);
            if(d[y] > maxx){
     
                maxx = d[y];
                maxid = y;
            }
        }
    }
    return maxid;
}

int main()
{
     
    scanf("%d%d", &n, &m);
    memset(head, -1, sizeof head);
    for(int i = 1; i <= m; ++ i){
     
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        add(x, y, z);
        add(y, x, z);
    }
    int p, q;
    p = bfs(1);
    q = bfs(p);
    ll ans = d[q];//the length of AB
    for(int i = 1; i <= n; ++ i){
     
        copy_d[i] = d[i];
    }
    bfs(q);
    ll res = 0;
    for(int i = 1; i <= n; ++ i){
     
        res = max(res, min(d[i], copy_d[i]));//find the longest edges among the remaining edges
    }
    ans += res;
    printf("%lld\n", ans);
    return 0;
}

你可能感兴趣的:(#,树的直径)