樹的重心定義為,當把節點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;
}