“一切都会好起来的。”|

zplqwq

园龄:3年10个月粉丝:25关注:14

2021-09-23 08:53阅读: 75评论: 0推荐: 0

树的直径与重心

Part I: 树的直径

定义:树上最远的两个点。

大致做法:两次 dfs .

第一次我们对任意一个节点跑 dfs 求出书上离他最远的点设为 q 则下一次我们以 q 为根再跑一遍 dfs 到达另一个最远结点。最后可以证明这两个节点就是树的直径。

代码:

//树的直径
void dfs(int u, int fa) {//u: 当前搜索到的节点 fa 这个节点的父亲节点
for (int v : E[u]) {//枚举出边
if (v == fa) continue;//如果这个出边回到他的父亲,那么过掉
d[v] = d[u] + 1;
if (d[v] > d[c]) c = v;//更新
dfs(v, u);//继续往下跑
}
}

Part II: 树的重心

大致做法:继续跑 dfs .

dfs 中计算每个子树的大小,记录“向下”的子树的最大大小,利用总点数 - 当前子树(这里的子树指有根树的子树)的大小得到“向上”的子树的大小,然后就可以依据定义找到重心了。

但其实这句话不好理解,感觉看代码会好很多。

//树的重心
void GetCentroid(int cur, int fa) { //cur 和 fa 分别是当前搜索到的节点和父亲节点
size[cur] = 1;//无论如何这个节点的大小至少是1吧
weight[cur] = 0;//暂时初始化的时候这个点没有子树
for (int i = head[cur]; i != -1; i = e[i].nxt) {//开始遍历
if (e[i].to != fa) { // e[i].to 表示这条有向边所通向的节点。
GetCentroid(e[i].to, cur);//继续往下搜索
size[cur] += size[e[i].to];//因为有子树了嘛,所以大小要直接加上他那个子树的大小
weight[cur] = max(weight[cur], size[e[i].to]);//取个最大值算重量
}
}
weight[cur] = max(weight[cur], n - size[cur]);//不好解释,就是相当于有一部分会没有被记录到,即这个节点“向上看”的子树,然而也就这一个没有记录到,因此我们直接把当前的最大值和 n减去当前的大小做过比较就可以求出来了。
if (weight[cur] <= n / 2) { // 依照树的重心的定义统计
centroid[centroid[0] != 0] = cur;
}
}

本文作者:zplqwq

本文链接:https://www.cnblogs.com/zplqwq/p/15322664.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   zplqwq  阅读(75)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示