树的直径与重心
定义:树上最远的两个点。
大致做法:两次 .
第一次我们对任意一个节点跑 求出书上离他最远的点设为 q
则下一次我们以 q
为根再跑一遍 到达另一个最远结点。最后可以证明这两个节点就是树的直径。
代码:
//树的直径 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);//继续往下跑 } }
大致做法:继续跑 .
在 中计算每个子树的大小,记录“向下”的子树的最大大小,利用总点数 - 当前子树(这里的子树指有根树的子树)的大小得到“向上”的子树的大小,然后就可以依据定义找到重心了。
但其实这句话不好理解,感觉看代码会好很多。
//树的重心 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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步