【題解】求樹的重心

2020-10-05 22:00:04

定義

樹的重心定義為,當把節點x去掉後,其最大子樹的節點個數最少(或者說成最大連通塊的節點數最少),那麼節點x就是樹的重心。
通俗的理解:這個點去掉後,剩下的聯通塊儘量平均

演演算法:

樹上任選一結點 u u u 開始 DFS,沿路統計其所有子樹的大小和以它為根的子樹的大小,這樣也就可以得到一個點所有子樹的大小及的大小

還有一個問題,如果這個點不是根節點,那麼刪掉後剩下的連通塊不止有他的子樹,還有他上面的部分,這部分可以由總結點減去他自己的子樹大小得到

我們知道一個性質:刪除重心後所得的所有子樹,節點數不超過原樹的1/2,那麼我們使用這個性質來判斷一個點是否為重心即可

程式碼:

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int MAXN=105;
vector<int> g[MAXN];
int dp[MAXN];
bool vis[MAXN];
int ans[MAXN];
int len=0;
int n;
void dfs(int x,int to){
	dp[x]=1;
	bool flag=true;
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		if(!vis[y]){
			vis[y]=true;
			dfs(y,x);
			dp[x]+=dp[y];
			if(dp[y]>n/2){
				flag=false;
			}
		}
	}
	if(n-dp[x]>n/2){
		flag=false;
	}
	if(flag){
		ans[++len]=x;
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n-1;i++){
		int u,v;
		scanf("%d %d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,-1);
	printf("%d\n",len);//有多少個重心
	
	for(int i=1;i<=len;i++){
		printf("%d\n",ans[i]);//輸出每一個重心
	}
return 0;
}