LIGHGTOJ 1094 Farthest Nodes in a Tree (树的直径,模板)

LIGHGTOJ 1094 Farthest Nodes in a Tree

题目传送门

题意:

给出你一棵树和每条边的边权,让你找出树上的两点,满足这两点之间的路径权值和最大。求这个权值和。

解题过程:

这题是一道模板题,就是让你求树的直径(树上最远点对),而方法也很简单,只需要做两遍DFS就行了。随机选取一个点,第一遍DFS找到距离这个点最远的点,该点就是树的直径的一个端点,然后以那个点为起点,再次DFS一遍,找到的最远的点就是另一个端点。
下面是证明过程:
首先给出一幅图:



我们假设S-U-T是这棵树的直径,然后我们随机选中一个点,如果选中的这个点是在树的直径上的(假设为图中的U点),那么这个点搜到的最远点一定是T或者S。
这是命题一,证明:假设搜到的点并不是S或者T,而是X,那么说明dis(U,S)或dis(U,T)要小于dis(U,X),那么这就与我们最初假设S-U-T为直径的结论不符合了。因为这样就有了一条更长的路径T-U-X或者S-U-X应该作为直径,故命题一正确。
如果选中的这个点不是在树的直径上(假设为途中的V点),那么从这个点搜到的最远的点也一定是T或者S。
这是命题二,证明:假设搜到的点并不是S或者T,而是X,那么说明dis(V,S)或dis(V,T)要小于dis(V,X),那么这同样与我们最初假设S-U-T为直径的结论不符合了。因为这样有了一条更长的路径T-U-V-X或者S-U-V-X应该作为直径,故命题二正确。

这两个命题证明完毕之后,我们就可以知道随机选一个点搜到的最远的点一定是树的直径的端点,那么再次DFS一遍之后就可以找出另一个端点,两点之间的距离就是树的直径。

AC代码:

#include<stdio.h>
#include<vector>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=300005;

struct edge
{
    int to;
    int dis;
    edge(int to,int dis):to(to),dis(dis) {}
};

vector<edge>e[maxn];

int T;
int n;
int dist=0;
int farthest;

void dfs(int fa,int x,int lenth)
{
    for(int i=0;i<e[x].size();i++)
    {
        if(e[x][i].to!=fa)
        dfs(x,e[x][i].to,lenth+e[x][i].dis);
    }
    if(dist<lenth)
    {
        dist=lenth;
        farthest=x;
    }
}

int main()
{
    scanf("%d",&T);
    for(int j=1;j<=T;j++)
    {
        for(int i=0;i<=300005;i++)
        e[i].clear();
        dist=0;

        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int s,t,dis;
            scanf("%d%d%d",&s,&t,&dis);
            e[s].push_back(edge(t,dis));
            e[t].push_back(edge(s,dis));
        }
        dfs(0,0,0);
        dist=0;
        dfs(farthest,farthest,0);
        printf("Case %d: %d
",j,dist);
    }
    return 0;
}

本人蒟蒻OIer一枚,欢迎加QQ:840776708一起学习蛤。

「我不敢下苦功琢磨自己,怕终于知道自己并非珠玉;然而心中既存着一丝希冀,便又不肯甘心与瓦砾为伍。」
原文地址:https://www.cnblogs.com/Apocrypha/p/9433662.html