树的重心&&直径
树的重心
定义:树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。(感谢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...