POJ - 1655 Balancing Act (树的重心)

题目链接

题意:给出一个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;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81813005