[xJOI3335] 树的直径(树上最远点)

题目大意就是求解一棵有边权的树上,距离最远的两点间的距离。
很容易想到Floyd或是暴力搜索的算法,但是这样过不了……

介绍一种非常经典的算法:选定任意一个点u作为根节点,从u开始BFS求出距离u最大的点s,再从s点出发BFS到距离s最大的点t,则dis(s,t)即为树的直径

证明:

(一):u在直径上:由于u为根节点,所以直径必为u到两子树的最大距离之和,这个证起来很简单。

(二):u不在直径上:

  ① 走着走着走到直径上,那么同(一)

  ②与直径不相交,这种情况事实上是不存在的,可以用不等式推一下。

Code

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int N = 100010;
const int INF = 715827882;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar();
    if(c == ‘-‘) w = -1, c = getchar();
    while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar();
    return x * w;
}
struct Edge{
    int to,cost;
    Edge(int _u, int _v): to(_u),cost(_v) {}
};
int n,m,ans,x,y,z,anss;
vector <Edge> G[N];
queue <int> q;
int vis[N],d[N];
inline void AddEdge(int u, int v, int w){
    Edge e(v,w);
    G[u].push_back(e);
}
inline void BFS(int s){
    memset(d,0,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s] = 0;
    while(!q.empty())q.pop();
    q.push(s);
    int cur,sz,to;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        if(vis[cur]) continue;
        vis[cur] = 1;
        sz = G[cur].size(),to;
        for(int i = 0; i < sz; ++i){
            to = G[cur][i].to;
            if(!vis[to]){
                d[to] = d[cur] + G[cur][i].cost;
                q.push(to);
            }
        }
    }
}
int main(){
//  freopen(".in","r",stdin);
    n = r;
    for(int i = 1; i < n; ++i){
        x=r,y=r,z=r;
        AddEdge(x,y,z);
        AddEdge(y,x,z);
    }
    BFS(1);
    int tmp,mx=0;
    for(int i = 1; i <= n; ++i){
        if(d[i] > mx){
            mx = d[i];
            tmp = i;
        }
    }
    BFS(tmp);
    mx = 0;
    for(int i = 1; i <= n; ++i){
        if(d[i] > mx){
            mx = d[i];
            tmp = i;
        }
    }
    printf("%d",d[tmp]);
    return 0;
}

原文地址:https://www.cnblogs.com/qixingzhi/p/9275225.html

时间: 2024-10-10 13:45:40

[xJOI3335] 树的直径(树上最远点)的相关文章

树的直径方法总结

定义: 直径 : 在圆上两点(不相交)之间最远的距离就是我们通常所说的直径. 树的直径 : 树上最远的两个节点之间的距离就被称为树的直径,连接这两点的路径被称为树的最长链. 求法: 1.树形 DP 2.两次 BFS 或者 两次 DFS 算法 1 : 树形 DP 优点 : 可以有效处理 负边权 缺点 : 对于记录路径的信息效率较低 简单分析 : 先通过递归的方式到叶子底部,然后通过自底向上的方式进行更新距离,找到最长路径. (看下图,可以得到这棵树的直径是经过根节点 1 的 路径最长的链 5 ->

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq10^5\). \(Solution\) 一个集合直径的两端点,在被划分为两个集合后一定是两个集合直径的四个端点中的两个. 即假设将\(S\)分为两个集合后,另外两个集合的直径的两端点分别为a,b和c,d,那么\(S\)集合的直径的两端点一定是a,b,c,d中的两个. 证明类似树的直径. 所以信息可

【BZOJ1912】【Apio2010】巡逻 树上最长链(才不是树的直径呢)

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45062689"); } 题解: 对于 k==0 的情况: 我们发现遍历一棵树最后回到原点,那么对于所有的边,我们都是走过去,再走回来. 答案 (n?1<<1) 对于 k==1 的情况 设每条边长度为1,然后树上找最长链,

树的直径

*总结的别人博客 树的直径(Diameter)是指树上的最长简单路.直径的求法:两遍BFS (or DFS)任选一点u为起点,对树进行BFS遍历,找出离u最远的点v以v为起点,再进行BFS遍历,找出离v最远的点w.则v到w的路径长度即为树的直径*简单证明于是原问题可以在O(E)时间内求出 关键在于证明第一次遍历的正确性,也就是对于任意点u,距离它最远的点v一定是最长路的一端.如果u在最长路上,那么v一定是最长路的一端.可以用反证法:假设v不是最长路的一端,则存在另一点v’使得(u→v’)是最长路

Cow Marathon(树的直径)

传送门 Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 5362   Accepted: 2634 Case Time Limit: 1000MS Description After hearing about the epidemic of obesity in the USA, Farmer John wants his cows to get more exercise, so he has

poj2631 求树的直径裸题

题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: 假设 s-t这条路径为树的直径,或者称为树上的最长路 现有结论,从任意一点u出发搜到的最远的点一定是s.t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路 证明: 1.设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则   dis(u

Gym - 100676H Capital City(边强连通分量 + 树的直径)

H. Capital City[ Color: Black ]Bahosain has become the president of Byteland, he is doing his best to make people's liveseasier. Now, he is working on improving road networks between the cities.If two cities are strongly connected, people can use BFS

hdu 2196 Computer 树的直径

Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers

【tyvj1520】 树的直径

描述 Description 树的直径,即这棵树中距离最远的两个结点的距离.每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径.树中相邻两个结点的距离为1.你的任务是:给定一棵树,求这棵树中距离最远的两个结点的距离. 输入格式 InputFormat 输入共n行第一行是一个正整数n,表示这棵树的结点数接下来的n-1行,每行三个正整数a,b,w.表示结点a和结点