ACM入门之树的重心

Posted 辉小歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM入门之树的重心相关的知识,希望对你有一定的参考价值。

树的重心的定义:
对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。
树的重心的性质:

  • 树中所有点到某个点的距离和中,到重心的距离和是最小的。如果有两个重心,那么到它们的距离和一样。
  • 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。
  • 两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。
    在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

例题一:

#include<bits/stdc++.h> 
using namespace std;
const int N=1e5*3+10;
int h[N],e[N],ne[N],idx;
void add(int a,int b)

	e[idx]=b,ne[idx]=h[a],h[a]=idx++;

int st[N],dist[N],n,m,ans=1e9;
int dfs(int u)

	st[u]=1;
	int sum=0,maxv=0;//是总的子树点的个数,最大的子树个数
	for(int i=h[u];i!=-1;i=ne[i])
	
		int j=e[i];
		if(st[j]) continue;
		int temp=dfs(j);
		sum+=temp,maxv=max(maxv,temp);
	
	maxv=max(maxv,n-sum-1);
	dist[u]=maxv;
	ans=min(ans,maxv);
	return sum+1;

int main(void)

	memset(h,-1,sizeof h);
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	
		int a,b; cin>>a>>b;
		add(a,b),add(b,a);
	
	dfs(1);
	for(int i=1;i<=n;i++) if(dist[i]==ans) cout<<i<<" ";
	return 0;

例题二:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
int h[N],e[N],ne[N],idx,st[N];
int n,ans=1e9;
void add(int a,int b)

    e[idx]=b,ne[idx]=h[a],h[a]=idx++;

int dfs(int u)

    int sum=0,maxv=0;
    st[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    
        int j=e[i];
        if(st[j]) continue;
        int temp=dfs(j);
        sum+=temp;
        maxv=max(maxv,temp);
    
    maxv=max(maxv,n-sum-1);
    ans=min(ans,maxv);
    return sum+1;

int main(void)

    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n-1;i++)
    
        int a,b; cin>>a>>b;
        add(a,b),add(b,a);
    
    dfs(1);
    cout<<ans<<endl;
    return 0;

以上是关于ACM入门之树的重心的主要内容,如果未能解决你的问题,请参考以下文章

『Balancing Act 树的重心』

求树的每个子树的重心

树的重心

求树的重心

[算法模版]树的重心和直径

CSP2019 树的重心 题解