树的直径(图论)
Part 1 有根树的直径
对于一棵无根树,我们可以先确定一个结点为根,以确定树的形态。注意,树的形态并不会影响答案,也就是说根是哪个点不重要。
在这里,我们假设树的边权是 $1$ 这种情况(一般情况)
下文所说的树都指有根树。
1. 定义:
一棵树上,集合 $T$ 的元素为任意两个点的距离(是唯一的),集合 $T$ 中最大的数便是树的直径。
2. DP 求法:
先设置两个数组 $dp1, dp2$. $dp1_i$ 表示从 $i$ 出发(向下走)的最长链的长度,$dp2_i$ 表示从 $i$ 出发(向下走)的次长链的长度,同时定义 $dp1_i$ 和 $dp2_i$ 是两条不同的链(两个链没有重复的边)。
再设置数组 $dp$. $dp_i$ 表示以 $i$ 为根节点的子树的直径。
算法流程:
STEP 1 求出 $dp1$, $dp2$:
考虑用递归求解:
void dfs(int x){ //dfs(x) 可求出 dp1[x] 与 dp2[x]
循环考察结点 x 的所有孩子节点(毕竟最后的次长/最长链一定会包含一条x的出边)
对于每一个孩子结点 u:
1° dp1[u] + 1 < dp2[x]: dp1[x] 和 dp2[x] 都不用更新
2° dp2[x] < dp1[u] + 1 < dp1[x]: dp1[x] 不用更新, dp2[x] = dp1[u] + 1
3° dp1[u] + 1 >= dp1[x]: dp2[x]=dp1[x], dp1[x] = dp1[u] + 1
}
STEP 2 求出 $dp$:
记以 $i$ 为根的子树为 $Tree_i$
对于 $dp_i$, 我们需要讨论这两大情况:最后的答案即 $Tree_i$ 的直径有可能经过结点 $i$, 或不经过结点 $i$
直径不经过结点 $i$ 就代表它一定在 $Tree_i$ 的任一子树里(注意 $Tree_i$ 的子树和子树之间是互相独立的),所以我们需要枚举在每一个子树的情况。
对于经过结点 $i$ 这一种情况,$dp_i=max(dp_i, dp1_i+dp2_i)$
3. 树的直径的性质
若一棵树有多个直径,则这些直径都经过其中点。
Part 2 题目——数字转化题解
我们先规定对于任意一种转化关系(x, y), 若 $y$ 为约数和,我们让 $y$ 成为 $x$ 的父亲。
因为对于每个数,都只会有一个约数和,所以每个结点只有一个父亲,所以最后建出来的是树。
然后找出所有子树跑树的直径再取 max 即可。

浙公网安备 33010602011771号