树的重心&&直径

树的重心

定义:树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。(感谢bai度百科)

所以怎么实现呢?

找一个点,算它的最大(子树,n-自身大小)的大小,当它最小的时候,那么这个点就是树的重心。

代码如下:

 1 void dfs(int x,int fa){//树的重心 
 2     size[x]=1;int max_part=0;
 3     for(int i=head[x];i;i=nex[i]){
 4         int y=to[i];
 5         if(y==fa) continue;
 6         dfs(y);
 7         size[x]+=size[y];
 8         max_part=max(max_part,size[y]);
 9     }
10     max_part=max(max_part,n-size[x]);
11     if(max_part<ans){
12         ans=max_part;
13         pos=x;
14     }
15 }

树的直径

就是树上的最大距离,一共有两种实现方式。

1、dfs/bfs

从任意一个点,寻找与它距离最大的点A,再找与点A距离最大的点B,AB间的距离就是直径的长度

大致代码如下:

 1 int dfs(int x,int fa){
 2     end[x]=x;
 3     int maxn=0;
 4     for(int i=head[x];i;i=e[i].nex){
 5         int y=e[i].to;
 6         if(y==fa) continue;
 7         int kkk=dfs(y,x);
 8         if(maxn<kkk+e[i].val){
 9             maxn=kkk+e[i].val;
10             end[x]=end[y];
11         }
12     }
13     return maxn;
14 }
15 signed main(){
16     cin>>n>>k;
17     tot=1;
18     for(int i=1;i<n;i++){
19         int u,v;
20         cin>>u>>v;
21         add(u,v,1);
22         add(v,u,1);
23     }
24     dfs(1,0);
25     int kkk=end[1];
26     l=dfs(kkk,0);
27     cout<<l;  
28     return 0;
29 }

2、树形DP

寻找每个点x子树中的最长链和次长链,分别用dp[x][0]与dp[x][1]表示,注意这两条链不能来自同一子树。那么过点x的最大距离就是dp[x][0]+dp[x][1]了;

直径就是最大的dp[x][0]+dp[x][1](1≤x≤n)

代码如下:

 1 void ddp(int x,int fa){
 2     for(int i=head[x];i;i=e[i].nex){
 3         int y=e[i].to;
 4         if(y==fa) continue;
 5         ddp(y,x);
 6         if(dp[x][0]<=dp[y][0]+e[i].val){
 7             dp[x][1]=dp[x][0];
 8             dp[x][0]=dp[y][0]+e[i].val;
 9         }
10         else if(dp[x][1]<=dp[y][0]+e[i].val){
11             dp[x][1]=dp[y][0]+e[i].val;
12         }
13     }
14 }

调用的时候这么写

ddp(1,0);
for(int i=1;i<=n;i++){
    max_len=max(max_len,dp[i][0]+dp[i][1]);
}

注意:

树的直径bfs/dfs中注意end[]数组,DP中注意更新dp[x][1]

THE END...

posted @ 2021-02-01 11:31  001A  阅读(14)  评论(0编辑  收藏  举报