定义:
对于一个 n 个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的节点数最小。
性质:
以树的重心为根的有根树,最大子树大小不超过 。( 即树的高度 <= log(n) )
思路:
先随意以一点为根,dfs处理每个节点的子树大小 siz[i] ,dfs回溯到 i 点时计算以 i 为根的情况下,最大子树大小为:
maxsubtree = max( siz[son1],siz[son2],...,siz[sonk],n-siz[i] ) 。(soni为当前 i 的子节点)
Code:(POJ 1655)
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX = 20000 + 10;
const ll mod = 1e9 + 7;
int n;
vector<int>mp[MAX];
int siz[MAX];
int rt, minsubtree;
void dfs(int root, int fa)
{
siz[root] = 1;
int maxsubtree = 0;
for (int i = 0; i < mp[root].size(); i++) {
int v = mp[root][i];
if (v == fa) continue;
dfs(v, root);
siz[root] += siz[v];
maxsubtree = max(maxsubtree, siz[v]);
}
maxsubtree = max(maxsubtree, n - siz[root]);
if (maxsubtree <= minsubtree) {
if (maxsubtree == minsubtree)
rt = min(rt, root);
else
rt = root;
minsubtree = maxsubtree;
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
//初始化
memset(siz, 0, sizeof(siz));
for (int i = 1; i <= n; i++) {
mp[i].clear();
}
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
mp[u].push_back(v);
mp[v].push_back(u);
}
//rt为该树的重心
rt = 0;
//minsubtree为以rt为根时的最大子树大小
minsubtree = 1e9 + 7;
dfs(1, -1);
printf("%d %d\n", rt, minsubtree);
}
return 0;
}