Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree in the forest T created by deleting that
node from T.
For example, consider the tree:
Deleting node 4 yields two trees whose member nodes are {5} and {1,2,3,6,7}. The larger of these two trees has five nodes, thus the balance of node 4 is five. Deleting node 1 yields a forest of three trees of equal size: {2,6}, {3,7}, and {4,5}. Each of these trees has two nodes, so the balance of node 1 is two.
For each input tree, calculate the node that has the minimum balance. If multiple nodes have equal balance, output the one with the lowest number.
Input
1 7 2 6 1 2 1 4 4 5 3 7 3 1
1 2
题目大概:
给出一棵树,找出它的重心是哪个节点,它的最小额度是多少(即最大子树的结点数)。
思路:
首先要知道重心定义,
树的重心是,与重心相连的所有子树中,结点数最多的子树 是所有节点的最多子树中最少的。
然后就dfs遍求出最小的额度。然后从1开始判断就可以了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n;
int dp[20005];
int d[20005];
int head[20005];
int minshu,no;
int ans;
struct shu
{
int v;
int next;
}tr[40010];
void add(int q,int w)
{
tr[ans].v=w;
tr[ans].next=head[q];
head[q]=ans++;
}
void dfs(int x,int pa)
{
d[x]=1;
int maxshu=-20005;
for(int i=head[x];i!=-1;i=tr[i].next)
{
int son=tr[i].v;
if(son!=pa)
{
dfs(son,x);
d[x]+=d[son];
maxshu=max(maxshu,d[son]);
}
}
dp[x]=max(maxshu,n-d[x]);
if(minshu>dp[x])
{
minshu=dp[x];
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
memset(d,0,sizeof(d));
memset(head,-1,sizeof(head));
ans=0;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int q,w;
scanf("%d%d",&q,&w);
add(q,w);
add(w,q);
}
minshu=20005;
no=0;
dfs(1,0);
for(int i=n;i>=1;i--)
{
if(minshu==dp[i])
{
no=i;
}
}
printf("%d %d\n",no,minshu);
}
return 0;
}