【定义】

给定一棵树,树中的每条边都有一个权值。

  • 树中两点的距离:连接两点的路径边权之和
  • 树的直径:树中最远的两个节点之间的距离
  • 树的最长链:连接树中最远的两个结点的路径

【实现】

树的直径通常有两种求法,时间复杂度均为O(n)。

假设树以 n 个点 n-1 条边的无向图形式给出,存储在邻接表中。

1.两次DFS求树的直径

通过两次 dfs 可以求树的直径,且更容易计算出直径上的具体结点

  1. 从任意结点出发,通过 dfs 对树进行一次遍历,求出于出发点距离最远的结点,记为 st
  2. 从结点 st 出发,通过 dfs 对树再进行一次遍历,求出于 st 距离最远的结点,记为 ed

则:st 到 ed 的路径就是树的直径

在第 2 步的遍历中,可以记录下来每个点第一次被访问的前驱节点,最后从 q 递归到 p,即可得到直径的具体方案

struct Edge {int to, val;int next;Edge(){}Edge(int to,int val,int next):to(to),val(val),next(next){}
} edge[N];
int n;
int head[N], tot;
int dis[N], maxx, id;
int st, ed, diameter;//起点、终点、直径
int disSt[N], disEd[N];//起点、终点分别到每个点的距离
void addEdge(int from, int to, int val) {edge[++tot].to = to;edge[tot].val = val;edge[tot].next = head[from];head[from] = tot;
}
void dfs(int x, int father) {for (int i = head[x]; i != -1; i = edge[i].next) {int y = edge[i].to;int val = edge[i].val;if (y == father)continue;dis[y] = dis[x] + val;if(dis[y]>maxx){maxx = dis[y];id = y;}dfs(y, x);}
}
void calcDiameter(){//第一遍dfsmaxx = 0;id = 1;dfs(1, 0);st = id;//第二遍dfsmaxx = 0;dis[st] = 0;dfs(st, 0);ed = id;diameter = maxx; //树的直径for (int i = 1; i <= n; i++)disSt[i] = dis[i];dis[ed] = 0;dfs(ed, 0);for (int i = 1; i <= n; i++)disEd[i] = dis[i];
}int main() {scanf("%d", &n);memset(head, -1, sizeof(head));for (int i = 1; i <= n - 1; i++) {int x, y, val;scanf("%d%d%d", &x, &y, &val);addEdge(x, y, val);addEdge(y, x, val);}calcDiameter();printf("%d %d\n", st, ed);printf("%d\n", diameter);return 0;
}

2.树形DP求树的直径

设 1 号节点为根,n 个点 n-1 条边的无向图就可以看做有根树

设 dis1[x] 表示从点 x 到以 x 为根的子树中叶结点的最长链, pos1[x] 表示 dis1[x] 在哪个点更新;dis2[x] 表示从点 x 到以 x 为根的子树中叶结点的次长链,pos2[x] 表示 dis2[x] 在哪个点更新,且要求两条链不能有交集。

这样一来,对于任意一点 i,经过点 i 的最长链的分为两个部分:i 的最长链 dis1[i]、i 的次长链 dis2[i]

那么,整棵树的直径就是

struct Edge {int to, val;int next;Edge(){}Edge(int to,int val,int next):to(to),val(val),next(next){}
} edge[N];
int n;
int head[N], tot;
int dis1[N], dis2[N];//分别维护第i个点的最长链、次长链
int pos1[N],pos2[N];//分别维护dis1[i]、dis2[i]从哪个点更新
void addEdge(int from, int to, int val) {edge[++tot].to = to;edge[tot].val = val;edge[tot].next = head[from];head[from] = tot;
}
void dfs(int x, int father) {for (int i = head[x]; i != -1; i = edge[i].next) {int y = edge[i].to;int val = edge[i].val;if (y == father)continue;dfs(y, x);if (dis1[y] + val > dis1[x]) {dis2[x] = dis1[x];dis1[x] = dis1[y] + val;pos2[x] = pos1[x];pos1[x] = y;} else if (dis1[y] + val > dis2[x]) {dis2[x] = dis1[y] + val;pos2[x] = y;}}
}
int main() {scanf("%d", &n);memset(head, -1, sizeof(head));for (int i = 1; i <= n - 1; i++) {int x, y, val;scanf("%d%d%d", &x, &y, &val);addEdge(x, y, val);addEdge(y, x, val);}dfs(1, 0);int diameter = -INF;for (int i = 1; i <= n; i++)diameter = max(dis1[i] + dis2[i], diameter);printf("%d", diameter);return 0;
}

树形结构 —— 树与二叉树 —— 树的直径相关推荐

  1. 6.4 树和二叉树-树和森林

    树和二叉树-树和森林 1. 树和森林的表示方法 1.1 树的三种存储结构-`双亲`表示法 1.2 树的三种存储结构-`孩子链表`表示法 1.3 树的三种存储结构-`孩子兄弟(二叉链表)(二叉树)`表示 ...

  2. PHP算法 《树形结构》 之 伸展树(1) - 基本概念

    伸展树的介绍 1.出处:http://dongxicheng.org/structure/splay-tree/ A. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Bin ...

  3. 数据库树形结构,EasyUI Tree 树

    通过 $.fn.tree.defaults 重写默认的 defaults. 树(tree)在网页中以树形结构显示分层数据.它向用户提供展开.折叠.拖拽.编辑和异步加载功能. 树的数据格式(Tree D ...

  4. 树形结构 —— 树与二叉树 —— 树的中心

    [概述] 树的中心问题是指:当给出 n 个结点与 n-1 条边后,要选定一个点作为整棵树的根结点,使得从该点到每个叶结点的最长路径最短. 树的中心问题主要有两种方法:DFS/BFS 进行搜索.树形 D ...

  5. 树形结构 —— 树与二叉树 —— 树的重心

    [概述] 树的重心也叫树的质心,对于一棵具有 n 个结点的无根树,找到一个点,使得将树变为以该点为根的有根树时,最大子树的结点数最小. 简单来说,就是给定一棵 n 个点的树,当删除某点 x 后,使得最 ...

  6. 树形结构 —— 树与二叉树 —— 树的数据生成器

    为方便测试数据,给出一个树的数据生成器. 树的结点为 1~10 个,边权为 1~100,各点编号随机化 struct Edge {int x, y;int dis; } edge[N]; int n, ...

  7. 树形结构 —— 树与二叉树

    [概述] 树是一种非线性的.递归定义的有序数据结构,能很好地描述有分支和层次特性的数据集合. 二叉树是树的一种形态,是 n 个结点的有限集合,该集合或为空集(空二叉树),或由一个根结点与两棵互不相交的 ...

  8. 数据结构--树和二叉树

    文章目录 树和二叉树 树 1.树的定义 2.树的逻辑表示 3.树的基本术语: 4.树的性质 5.树的基本运算 二叉树 二叉树的存储结构 二叉树的遍历 树和二叉树 树 1.树的定义 2.树的逻辑表示 树 ...

  9. 数据结构与算法——树和二叉树***

    第五章 :树和二叉树 树和图是两种重要的非线性结构.线性结构中结点具有唯一前驱和唯一后继的关系,而非线性结构中结点之间的关系不再具有这种唯一性.其中,树形结构中结点间的关系是前驱唯一而后继不唯一,即元 ...

最新文章

  1. pandas重置dataframe的索引(reset_index)、如果索引不匹配dataframe操作时候的问题、重置索引(不设置drop=true)远索引生成新的数据列
  2. 学号 20172326 《程序设计与数据结构》第三周学习总结
  3. 饱和气压与温度的关系_凯米斯小课堂 | 溶解氧与水产养殖的关系
  4. JVM垃圾回收的时候如何确定垃圾?什么是GC Roots?
  5. Class对象和Java反射机制
  6. 绵阳python培训_《绵》字意思读音、组词解释及笔画数 - 新华字典 - 911查询
  7. 中南林业科技大学的计算机研究生分数线,2019中南林业科技大学研究生分数线汇总(含2016-2019历年复试)...
  8. WSDL文件生成WEB service server端C#程序
  9. 秒懂系列 | 史上最简单的Python Django入门教程
  10. Markdown标题、行首缩进、换行。csdn(1)
  11. angularJs的spa页面切换以及ngRoute模块
  12. await和async
  13. java下载m3u8视频,解密并合并ts(一)
  14. 健康管理师考试重点详解!(基础知识篇)
  15. Vulkan编程指南翻译 第六章 着色器和管线 第2节 SPIR-V 概述
  16. mysql中的comment_请问一下在mysql中的 COMMENT 有什么作用吗??
  17. Laya Tween循环
  18. 荣耀Magic 3Pro 充电架构分析
  19. 你应该掌握的浏览器相关知识
  20. 英才计划计算机潜质测评试题,2018年“英才计划”综合实践活动通知

热门文章

  1. 程序猿们,如果你不想跑偏,就千万别读这4本书!
  2. 北大教授郑也夫斗胆谈了7个天大的问题,每个都非常狠,也很现实
  3. Cortex-M3栈内存操作
  4. 求职和跳槽最好的月份要来了吗
  5. 逼自己玩命学了3个多月,整理出了这份549个分支的技术脑图,分享给你
  6. 有了这份程序员面试指南,你离大厂Offer还远吗?| 附推荐书籍
  7. 从3000米高空,一跃而下…
  8. 理解JQuery中的data()使用方法
  9. h5 video全屏播放
  10. 算法我也不知道有没有下一个---一个题目的开端(索引堆与图)