https://vjudge.net/problem/POJ-1655
给定m个点,和m-1个边,问你去掉一个点,使其最大子树最小,(即尽可能的平衡),输出那个点和最大的子树,如果有很多 点的最大子树 一样大, 那么就输出标号最小的。
这个带你就是树的重心啦hiahia
假设从1点开始dfs,在遍历黄色点的时候,子节点是两个红色的,得到的siz都是0,这俩点没有子树啊qwq,然后加1,所有这点就是1,
然后在dfs序之前的那个子树,就是绿色的子树,但是要减去黄色点本身。qwq
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <list>
#include <algorithm>
#include <climits>
using namespace std;
/*树的重心,就是刨掉一个点之后,最大子树最小。
苟神说,树形dp可以很方便的求数的重心。
*/
const int maxn=4e5+20;
struct Node{
int to;
int next;
}node[maxn];
int len;
int head[maxn];
void add(int a,int b){
node[len].to=b;
node[len].next=head[a];
head[a]=len++;
}
int min_siz;
int ans_bh;
int m;
bool vis[maxn];
void Init(){
len=0;
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
min_siz=1e8+8;
}
int dfs(int x){
int siz=0;
vis[x]=true;
int all=0;
for(int i=head[x];i!=-1;i=node[i].next){
int to=node[i].to;
if(vis[to]) continue;
int siz_child=dfs(to);
siz=max(siz,siz_child+1);//每个孩子的节点。加的1是本身。
all+=(siz_child+1);//都加起来,为了求dfs序之前的点。qwq
}
siz=max(m-all-1,siz);//求dfs序之前的那个子树。
if(siz<min_siz||(siz==min_siz&&x<ans_bh)){
min_siz=siz;//求最小,并且标号最小,
ans_bh=x;
}
return all;
}
int main()
{ int t;
int a,b;
scanf("%d",&t);
while(t--){
Init();
scanf("%d",&m);
for(int i=0;i<m-1;i++){
scanf("%d%d",&a,&b);
add(b,a);
add(a,b);
}
dfs(1);
printf("%d %d\n",ans_bh,min_siz);
}
return 0;
}