重中之重(别忘了我(蒟蒻)名字的翻译)
最基础的树的直径和重心
我是分割线---------------------------------------------------------------------------------------------------------
树的直径
我是分割线---------------------------------------------------------------------------------------------------------
树的直径(Diameter)是指树上的最长简单路没错不是它有多宽(e.g.)。
直径的求法:两遍搜索 (BFS or DFS)。
过程:任选一点w为起点,对树进行搜索,找出离w最远的点u。以u为起点,再进行搜索,找出离u最远的点v。则u到v的路径长度即为树的直径。
简单证明:
如果w在直径上,那么u一定是直径的一个端点。反证:若u不是端点,则从直径一端点到w再到u的距离比直径更长,与假设矛盾。
如果w不在直径上,且w到其距最远点u的路径与直径一定有一交点c,那么由上一个证明可知,u是直径的一个端点。
我是分割线---------------------------------------------------------------------------------------------------------
上方证明的过程
如果w到最远点u的路径与直径没有交点,设直径的两端为S与T。
wu为w引出的最长路:
wu>wc+ct
st为直径(即st应最长)But:
sc+cw+wu>sc+cw+wc+ct
而:
sc+ct=st(最长路??)
so su比直径还长吗?
so u一定在直径上。
因此w到最远点u的路径与直径必有交点。
S-----------c-----------T
|
|
w------u
我是分割线---------------------------------------------------------------------------------------------------------
我是分割线---------------------------------------------------------------------------------------------------------
树的重心
算法流程
首先,利用前向星存边建立边表。由于无向,所以要连两次边。我们用一次 dfs() 建立以1为根节点时每个结点所在子树的结点数。
接下来考虑把这个点删掉的结果,如果一个非根结点有 p 个儿子,那么删掉这个点之后会有 p+1 个连通分量,因为这个结点不是根节点,那么除了这个结点及它的所有子树外还有一个连通分量,我们将之称为这个结点的上方子树。接下来,计算这些子树(包括上方子树)的 size (指以当前节点为父亲或祖宗的节点数总和)再从中找个最大值,因为总共有 n 个结点所以有 n 个最大值,接下来在其中挑一个最小的即可,当这个值取到最小时的那个结点就是这棵树的重心。
size 的计算方法:
结点 u 的子树,直接利用 size 即可。
结点 u 的上方子树,可以利用求补集的思想,总共有 n 个结点,这个结点及其所有子树的结点和为 size(u), 那么它的上方子树的 size 就是 n−size(u) 。
附图一张(看不懂看图自己摸拟):
代码
重心进阶(自带例题和代码)