① 两次dfs

方法:先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是是的直径

证明如下:

①若P已经在直径上,根据树的直径的定义可知Q也在直径上且为直径的一个端点

②若P不在直径上,我们用反证法,假设此时WQ不是直径,AB是直径

--->若AB与PQ有交点C,由于P到Q最远,那么PC+CQ>PC+CA,所以CQ>CA,易得CQ+CB>CA+CB,即CQ+CB>AB,与AB是直径矛盾,不成立,如下图(其中AB,PQ不一定是

直线,画成直线是为了方便):

--->若AB与PQ没有交点,M为AB上任意一点,N为PQ上任意一点。首先还是NP+NQ>NQ+MN+MB,同时减掉NQ,得NP>MN+MB,易知NP+MN>MB,所NP+MN+MA>MB+MA,

即NP+MN+MA>AB,与AB是直径矛盾,所以这种情况也不成立,如下图:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100000
 6 using namespace std;
 7 inline int read()
 8 {
 9     int x=0;
10     bool f=1;
11     char c=getchar();
12     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
13     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
14     if(f) return x;
15     return 0-x;
16 }
17 struct node
18 {
19     int u,v,w,nex;
20 }edge[2*maxn+10];
21 int n,m,d[maxn+10],head[maxn+10],f_num,cnt=0,ans;
22 inline void add(int x,int y,int z)
23 {
24     cnt++;
25     edge[cnt].u=x;
26     edge[cnt].v=y;
27     edge[cnt].w=z;
28     edge[cnt].nex=head[x];
29     head[x]=cnt;
30 }
31 inline void dfs(int x,int fa)
32 {
33     if(ans<d[x])
34     {
35         ans=d[x];
36         f_num=x;
37     }
38     for(int i=head[x];i!=-1;i=edge[i].nex)
39     {
40         int j=edge[i].v;
41         if(j==fa)continue;
42         d[j]=d[x]+edge[i].w;
43         dfs(j,x);
44     }
45 }
46 int main()
47 {
48     memset(head,-1,sizeof(head));
49     n=read();m=read();
50     for(int i=1;i<=m;i++)
51     {
52         int x,y,z;
53         x=read();y=read();z=read();
54         add(x,y,z);
55         add(y,x,z);
56     }
57     dfs(1,0);
58     ans=0;
59     d[f_num]=0;
60     dfs(f_num,0);
61     printf("%d",ans);
62     return 0;
63 }

② 树形DP

对于每个节点我们要记录两个值:f1 [ i ] 表示以 i 为根的子树中,i 到叶子结点距离的最大值f2 [ i ] 表示以 i 为根的子树中,i 到叶子结点距离的次大值对于一个节点,它到叶子结点距

离的最大值和次大致所经 过的路径肯定是不一样的若j是i的儿子,那么(下面的 w [ i ][ j ] 表示 i 到 j 的路径长度):

若 f1 [ i ] < f1 [ j ] + w [ i ][ j ],f2 [ i ] =f1 [ i ],f1 [ i ] = f1 [ j ] + w [ i ][ j ];

否则,若 f2 [ i ] < f1 [ j ] + w [ i ][ j ],f2 [i ] = f1 [ j ] + w [ i ][ j ];

理解:这样做就是,先看能否更新最大值,若能,它的次大值就是原先的最大值,再更新它的最大值;若不能,就看能不能更新次大值,若能,就更新,不能就不管它

这样的话,最后的答案 answer = max { f1 [ i ] + f2[ i ] }

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100000
 6 #define INF 2147483647/2-1
 7 using namespace std;
 8 inline int read()
 9 {
10     int x=0;
11     bool f=1;
12     char c=getchar();
13     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
14     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
15     if(f) return x;
16     return 0-x;
17 }
18 int n,m,ans,f1[maxn+10],f2[maxn+10],head[maxn+10],cnt=0;
19 struct node
20 {
21     int u,v,w,nex;
22 }edge[2*maxn+10];
23 inline void add(int x,int y,int z)
24 {
25     cnt++;
26     edge[cnt].u=x;
27     edge[cnt].v=y;
28     edge[cnt].w=z;
29     edge[cnt].nex=head[x];
30     head[x]=cnt;
31 }
32 inline void dp(int x,int fa)
33 {
34     for(int i=head[x];i!=-1;i=edge[i].nex)
35     {
36         int j=edge[i].v;
37         if(j==fa)continue;
38         dp(j,x);
39         if(f1[x]<f1[j]+edge[i].w)
40         {
41             f2[x]=f1[x];
42             f1[x]=f1[j]+edge[i].w;
43         }
44         else if(f2[x]<f1[j]+edge[i].w)
45         {
46             f2[x]=f1[j]+edge[i].w;
47         }
48         ans=max(ans,f1[x]+f2[x]);
49     }
50 }
51 int main()
52 {
53     memset(head,-1,sizeof(head));
54     n=read();m=read();
55     for(int i=1;i<=m;i++)
56     {
57         int x,y,z;
58         x=read();y=read();z=read();
59         add(x,y,z);
60         add(y,x,z);
61     }
62     dp(1,0);
63     printf("%d",ans);
64     return 0;
65 }原文作者:forever_dreams 来源:CSDN
请各位大佬斧正(反正我不认识斧正是什么意思)

转载于:https://www.cnblogs.com/handsome-zyc/p/11237529.html

求树的直径(两种方法)相关推荐

  1. matlab 求矩阵秩,求矩阵秩的两种方法及MATLAB的应用

    摘    要: 高等代数是一门逻辑思维比较强和理论知识比较深的学科, 它具有丰富的数学知识, 涉及许多重要的数学思想, 其在数学领域的应用很广泛, 如行列式.矩阵的相关计算和求解线性方程组的解方面的应 ...

  2. C++求二叉树深度的两种方法

    今天在leetcode中碰到了求二叉树的深度问题,于是总结一下这两种方法 方法一是用递归的方法,方法二是借助队列和层序遍历的思想 #include<iostream> #include&l ...

  3. 获取树高度的两种方法与完全二叉树的判断

    树的高度 树的高度是节点高度的最大值. 每一层节点的高度如图所示. 方法一:递归 根节点的高度显然就是二叉树的高度. /** * 获取树的高度* @return*/ public int height ...

  4. 已知三点求平面的法向量 —— 两种方法

    最近学图形学时遇到了这个问题,PPT 给的大概是一个通过线性代数的方法求的,有点看不懂.加上线性代数早就忘光了,更加是一脸茫然.但是这个知识点在高中讲过,自己却怎么也记不起来了,直到今天突然记起来了, ...

  5. C++求字符串长度的两种方法

    针对于string类型的,可以采用strlen 针对于wstring类型的,可以采用_tcslen方法 实例代码: //字符串测试Unicode和ansi void strControl() {std ...

  6. 求互质数对的两种方法:欧拉函数和容斥原理

    1.HDU4135 首先,我们可以先求出1 ~ a - 1内与n互质的数,再求出1 ~ b内与n互质的数.最后利用前缀和算出来即可. #include <iostream> #includ ...

  7. C语言-求阶乘和的两种方法

    目录 方法一:递归法 方法二:循环法 fun.c文件 fun.h文件 main.c文件 方法一:递归法 /** 递归法 求阶乘和**/ long Factorial_sum_way1(int m){i ...

  8. 求树的直径的两种方法

    树的直径 树型dp求树的直径 优缺点: 优点为可以处理边权为负的情况,但不易得到直径的路径(指树的直径经过什么点). 代码模板: #include<bits/stdc++.h> using ...

  9. 牛客 Tree(最小深度总和)(两种方法求重心)难度⭐⭐⭐

    题目链接 牛妹有一张连通图,由n个点和n-1条边构成,也就是说这是一棵树,牛妹可以任意选择一个点为根,根的深度deprootdep_{root}deproot​​为0,对于任意一个非根的点,我们将他到 ...

  10. c语言求出两个最大素数,求两个正整数的最大公约数      思路:这是一个很基本的问题,最常见的就是两种方法,辗转相除法和辗转相减法。通式分别为 f(x, y) = f(y, x%y...

    求两个正整数的最大公约数 思路:这是一个很基本的问题,最常见的就是两种方法,辗转相除法和辗转相减法.通式分别为 f(x, y) = f(y, x%y), f(x, y) = f(y, x - y) ( ...

最新文章

  1. Apache日志配置参数说明
  2. python如何输出多个星号_如何将 Python 的一个类方法变为多个方法?
  3. HDU4000Fruit Ninja【树状数组+组合数】
  4. Linux 定制X86平台操作系统
  5. mysql最大连接数合理值_MySQL服务器最大连接数的合理设置
  6. 2015-01-11 在SQL2008创建一个数据库
  7. WinForm 自动完成控件实例代码简析
  8. mysql表文件创建_php文件创建mysql的表
  9. java的actioncontext_【疑惑】ActionContext ac = ActionContext.getContext();?
  10. C# Web Service 不使用服务引用直接调用方法(转)
  11. 罗技G29方向盘linux下的开发
  12. 【SAP-FICO详细教程】
  13. 哈佛幸福课 24人格力量测试
  14. WMB Commands
  15. Windows事件查看器介绍
  16. 手把手教你用keras搭建GAN
  17. Android技巧之相对高度使用
  18. 微信支付 postman_支付宝微信刷脸支付系统搭建服务商平台怎么做
  19. 如何利用无线技术有效预化工厂防爆炸事故?
  20. 怎么查看浪潮服务器型号,供应 浪潮服务器 各种型号

热门文章

  1. linux文件编码无法修改,在Linux系统中修改文本的字符编码的方法
  2. javaScript——原型
  3. Redis那些事(一) — Redis简介
  4. JS获取当前屏幕宽高
  5. 利用缓冲流读取跟写入
  6. swift版的StringAttribute
  7. poj1548Robots dfs实践
  8. Hibernate学习笔记--映射配置文件详解
  9. boot入门思想 spring_(第一讲)Spring Initializr-快速入门Spring Boot的最好选择
  10. (2)PCIE简介(学无止境)