树的重心

    科技2022-07-14  123

    解释:

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

    思路

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

    删除重心后所得的所有子树,节点数不超过原树的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; }
    Processed: 0.011, SQL: 8