树的重心

树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重

心后,生成的多棵树尽可能平衡.

poj 3107

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define Max 50010
using namespace std;

int n;
int Start[Max], Next[Max * 2], End[Max * 2];
int dex;
int son[Max];
int ans;
vector <int> V;

void Init() {
	memset(Start, 0, sizeof(Start));
	dex = 0;
	ans = Max;
	V.clear();
}

void BuildG(int a, int b) {
	Next[++dex] = Start[a];
	Start[a] = dex;
	End[dex] = b;
}

void dfs(int v, int fa) {
	son[v] = 0;
	int tmp, maxn = 0;
	for(int i = Start[v]; i; i = Next[i]) {
		int to = End[i];
		if(to != fa) {
			dfs(to, v);
			tmp = son[to] + 1;
			maxn = max(maxn, tmp);
			son[v] += son[to] + 1;
		}
	}
	maxn = max(maxn, n - 1 - son[v]);
	if(maxn < ans)
		ans = maxn, V.clear();
	if(maxn == ans)
		V.push_back(v);
}

int main() {
	while(~scanf("%d", &n)) {
		Init();
		int a, b;
		for(int i = 1; i < n; i++) {
			scanf("%d%d", &a, &b);
			BuildG(a, b);
			BuildG(b, a);
		}
		dfs(1, -1);
		sort(V.begin(), V.end());
		for(int i = 0; i < V.size(); i++) {
			printf("%d", V[i]);
			if(i < V.size() - 1)
				printf(" ");
		}
		printf("\n");
	}
	return 0;
}

poj 1655

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Max 20010
using namespace std;

int n;
int Start[Max], Next[Max * 2], End[Max * 2];
int dex;
int son[Max];
int ans, ansid;

void Init() {
	memset(Start, 0, sizeof(Start));
	dex = 0;
	ans = Max;
}

void BuildG(int a, int b) {
	Next[++dex] = Start[a];
	Start[a] = dex;
	End[dex] = b;
}

void dfs(int v, int fa) {
	son[v] = 0;
	int tmp, maxn = 0;
	for(int i = Start[v]; i; i = Next[i]) {
		int to = End[i];
		if(to != fa) {
			dfs(to, v);
			tmp = son[to] + 1;
			maxn = max(maxn, tmp);
			son[v] += son[to] + 1;
		}
	}
	maxn = max(maxn, n - 1 - son[v]);
	if(maxn < ans || maxn == ans && v < ansid)
		ansid = v, ans = maxn;
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		Init();
		scanf("%d", &n);
		int a, b;
		for(int i = 1; i < n; i++) {
			scanf("%d%d", &a, &b);
			BuildG(a, b);
			BuildG(b, a);
		}
		dfs(1, -1);
		printf("%d %d\n", ansid, ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值