树的直径(Diameter)是指树上的最长简单路。

直径的求法:两遍搜索 (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,那么(w->u)>(w->c)+(c->T),推出(w->u)+(S->c)+(w->c)>(S->c)+(c->T)=(S->T)与假设矛盾。

因此w到最远点u的路径与直径必有交点。

S-----------c-----------T

                 |

                w------u

 

树的重心

何谓重心

树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。

树的重心可以通过简单的两次搜索求出,第一遍搜索求出每个结点的子结点数量son[u],第二遍搜索找出使max{son[u],n-son[u]-1}最小的结点。

实际上这两步操作可以在一次遍历中解决。对结点u的每一个儿子v,递归的处理v,求出son[v],然后判断是否是结点数最多的子树,处理完所有子结点后,判断u是否为重心。

 1 struct CenterTree{
 2     int n;
 3     int ans;
 4     int siz;
 5     int son[maxn];
 6     void dfs(int u,int pa){
 7         son[u]=1;
 8         int res=0;
 9         for (int i=head[u];i!=-1;i=edges[i].next){
10             int v=edges[i].to;
11             if (v==pa) continue;
12             if (vis[v]) continue;
13             dfs(v,u);
14             son[u]+=son[v];
15             res=max(res,son[v]-1);
16         }
17         res=max(res,n-son[u]);
18         if (res<siz){
19             ans=u;
20             siz=res;
21         }
22     }
23     int getCenter(int x){
24         ans=0;
25         siz=INF;
26         dfs(x,-1);
27         return ans;
28     }
29 }Cent;
树的重心

相关文章:

  • 2021-04-19
  • 2022-12-23
  • 2021-10-14
  • 2022-12-23
  • 2021-09-13
  • 2021-10-26
  • 2022-02-12
猜你喜欢
  • 2021-10-01
  • 2021-05-17
  • 2021-12-14
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案