树的重心
题意: 求出删除某节点之后,分出来的树中最多节点的树的节点数最少,求出此节点;
思路:我们求出此节点的各个子树有多少个节点,分别记录,并计算总和(d数组)
然后在其遍历完之后,再最后再计算一下他父亲节点以及父亲节点所连接的其他节点的这一颗树的节点数;
所以,要删除此节点,就要记录一下删除之后出现的几颗子树的节点(上文已记录)
分为两部分,一部分是父亲,一部分是儿子,儿子在dfs的时候已经得出最大的那个
所以在此节点dfs完毕之后,再将这个最大的儿子与父亲那颗子树比较得出最后答案即可
1 #include<iostream> 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 typedef long long ll; 7 const int maxn=200005; 8 vector<int> tree[maxn]; 9 int n,minNode,minBalance; 10 //minNode当前重心节点 11 //minBalance当前重心节点的最大子树节点个数 12 int d[maxn]; 13 //d[i]表示以i为根的子树节点个数 14 void dfs(int u,int fa){ 15 d[u]=1; //节点本身 16 int maxSub=0,size=tree[u].size(); //maxSub为节点u的最大子树节点个数 17 for(int i=0;i<size;i++){ 18 int v=tree[u][i]; 19 if(v!=fa){ 20 dfs(v,u); 21 d[u]+=d[v]; 22 maxSub=max(maxSub,d[v]); 23 } 24 } 25 maxSub=max(maxSub,n-d[u]); 26 if(maxSub<minBalance){ 27 minNode=u; 28 minBalance=maxSub; 29 } 30 } 31 int main() 32 { 33 int t; 34 cin>>t; 35 while(t--){ 36 cin>>n; 37 for(int i=1;i<=n;i++) tree[i].clear(); 38 memset(d,0,sizeof(d)); 39 for(int i=1;i<n;i++){ 40 int u,v; 41 cin>>u>>v; 42 tree[u].push_back(v); 43 tree[v].push_back(u); 44 } 45 minNode=0; minBalance=0x3f3f3f3f; 46 dfs(1,0); 47 printf("%d %d\n",minNode,minBalance); 48 } 49 return 0; 50 }