To_Heart—题解——树的重心

解释:

树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值

思路

首先,我们得明白一个性质:

删除重心后所得的所有子树,节点数不超过原树的1/2;
这不是废话

通过这个性质,我们可以对重心进行求解

树上任选一点i,进行DFS,并统计该点所有子树的大小和以它为根的子树的大小,这样也就可以得到一个点所有子树的大小及的大小,如果它的大小大于了原树的一半,就说明它不是重心

还有一个问题,如果这个点不是根节点,那么删掉后剩下的连通块不止有他的子树,还有他上面的部分,这部分可以由原树所有节点减去他自己的子树大小得到

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;

vector<int> v[MAXN];
int dp[MAXN]={};
int cnt[MAXN]={};
int CNT=0,n;
bool f[MAXN]={};

void DP(int x){
	dp[x]=1;
	bool flag=1;
	//printf("%d %d\n",x,dp[x]);
	for(int i=0;i<v[x].size();i++){
		int y=v[x][i];
		if(f[y])
			continue;
		f[y]=1;
		DP(y);
		dp[x]+=dp[y];
		if(dp[y]>n/2){
			flag=0;
		}
	}
	if(n-dp[x]>n/2){
		flag=0;
	}
	if(flag){
		cnt[++CNT]=x;
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	f[1]=1;
	DP(1);
	printf("%d\n",CNT);
	sort(cnt+1,cnt+CNT+1);
	for(int i=1;i<=CNT;i++){
		printf("%d\n",cnt[i]);
	}
//	cout<<endl;
//	for(int i=1;i<=n;i++){
//		printf("%d ",dp[i]);
//	}
	return 0;
}
posted @ 2020-10-04 15:06  To_Heart  阅读(70)  评论(0)    收藏  举报