题意:给出一个t(t组样例),再给出一个n(表示1~n个结点),随后n-1行给出u,v(表示u和v联通)要求去掉1~n中一个结点使得拆分出来的所有子树的最大子树结点数最少.
题解:很明显树的重心裸题.
树的重心定义:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
树的重心可以通过简单的两次搜索求出,第一遍搜索求出每个结点的子结点数量son[u],第二遍搜索找出使max{son[u],n-son[u]-1}最小的结点。
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 1e5 + 500;
vector<int>e[maxn];
bool vis[maxn];
int son[maxn];
int n, ans, num;
void dfs(int u)
{
vis[u] = 1;
son[u] = 0;
int maxson = 0;//记录以该点为根的所有子树的最大结点数
for (int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if (!vis[v])
{
dfs(v);
son[u] += son[v] + 1;
maxson = max(maxson, son[v] + 1);
}
}
maxson = max(maxson, n - son[u] - 1);
if (maxson < ans) //取到最优的就是重心
{
ans = maxson;
num = u;
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
ans = inf;
for (int i = 0; i <= n; i++)
{
vis[i] = 0;
e[i].clear();
}
for (int i = 0; i < n - 1; i++)
{
int u, v;
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1);
printf("%d %d\n", num, ans);
}
return 0;
}