树的重心的定义:
在一棵树中,找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
通俗来说就是以这个点为根节点,找到他最大的衣蛾子树,然后让这个子树最小。
例题加模板:
POJ 1655
#include<iostream> #include<vector> #include<cstring> using namespace std; const int N=2E4+7; vector<int >ve[N]; bool mark[N]; int ans=N,pos; int n; int dfs(int x){ mark[x]=1; int sum=0;//sum为以x为根节点,其包含的点的总数目。 int s=0; for(int i=0;i<ve[x].size();i++){ if(mark[ve[x][i]]) continue ; int x1=dfs(ve[x][i]); s=max(s,x1);// sum+=x1; } s=max(s,n-sum-1);//以x为根节点,s是X下边的点集的最大值,n-sum-1是x点上边的点集的最大值 // ans=min(ans,s);//最大子树最小if(s<=ans){ if(s==ans){ pos=min(pos,x); } else { ans=s; pos=x; } } return sum+1; } void solve() { ans=N; memset(mark,0,sizeof mark); cin>>n; int x,y; for(int i=1;i<=n;i++) ve[i].clear(); for(int i=1;i<=n-1;i++){ cin>>x>>y; ve[x].push_back(y); ve[y].push_back(x); } dfs(1); cout<<pos<<" "<<ans<<endl; } int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) solve(); return 0; }
树的重心的一些性质:
1 树上所有的点到重心的距离和最小,可能会有两个重心,此时到这两个重心的距离和最小
2 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
3 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
4 一棵树最多有两个重心,并且这两个重心相邻