1. 程式人生 > >樹的重心【poj1655】

樹的重心【poj1655】

定義

的重心也叫的質心。對於一棵樹n個節點的無根樹,找到一個點,使得把樹變成以該點為根的有根樹時,最大子樹的結點數最小。換句話說,刪除這個點後最大連通塊(一定是樹)的結點數最小。

數的重心求法其實非常簡單,用到了簡單的樹形dp的思想。

你只要進行一次dfs,一邊求以當前節點為根的子樹的節點數,一邊統計出子樹中最大的有max{f[j]}個節點(j為i的兒子)和i節點上方的子樹大小為n-f[i]個節點。這樣就可以找到重心了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,cnt,T,a,b,mind,min0;
int d[50035],head[50035],nxt[50035],to[50035];
void add(int x,int y)
{
	cnt++;nxt[cnt]=head[x];to[cnt]=y;head[x]=cnt;
}
void dfs(int u,int fa)
{
	d[u]=1;
	int max0=0;
	for (int i=head[u];i;i=nxt[i])
	{
		int son=to[i];
		if (son==fa) continue;
		dfs(son,u);
		d[u]=d[u]+d[son];//統計以u節點為根的子樹的節點個數
		max0=max(max0,d[son]);
	}
	max0=max(max0,n-d[u]);
	if (min0>max0)
	{
		min0=max0;
		mind=u;
	}
}
int main()
{
	scanf("%d",&T);
	while (T>0)
	{
		T--;
		min0=1e9+7;
		cnt=0;
		memset(head,0,sizeof(head));
		scanf("%d",&n);
		for (int i=1;i<=n-1;i++) 
		{
			scanf("%d%d",&a,&b);
			add(a,b);
			add(b,a);
		}
		 dfs(1,0);
		printf("%d %d\n",mind,min0);
	}
}