#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn = 20010;
const int inf = 0x1fffffff;
typedef struct EDGE{
int node,Next;
}Edge;
Edge edge[maxn<<1];
int balance[maxn],recordnode[maxn],nodenum[maxn],t,n;
bool visit[maxn];
int cntEdge = 0;
inline void addEdge(int n1,int n2){
edge[cntEdge].node = n1; edge[cntEdge].Next = recordnode[n2]; recordnode[n2] = cntEdge++;
edge[cntEdge].node = n2; edge[cntEdge].Next = recordnode[n1]; recordnode[n1] = cntEdge++;
}
int dfs(int id){
int ans = 0, sum = 0,i;
visit[id] = 1;
for(i = recordnode[id]; i != -1; i = edge[i].Next){
int nodeid = edge[i].node;
if(!visit[nodeid]){
int t = dfs(nodeid);
sum += t;
if(ans < t)
ans = t;
}
}
//ans为以id的所有叶结点为根的子树所含结点的最大值
nodenum[id] = sum + 1;
int t = n - nodenum[id]; //删掉以id为根的子树后余下的所有结点
if(ans < t){
ans = t;
}
balance[id] = ans;
return nodenum[id];
}
int main(){
int i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
cntEdge = 0;
memset(visit,0,sizeof(visit));
memset(nodenum,0,sizeof(nodenum));
memset(recordnode,-1,sizeof(recordnode));
int node1,node2;
for(i = 1; i < n; ++i){
scanf("%d%d",&node1,&node2);
addEdge(node1,node2);
}
dfs(1);
int ans,index = -1;
bool ismax;
ans = inf;
for(i = 1; i <= n; ++i){
ismax = ans > balance[i];
ans = ismax?balance[i]:ans;
index = ismax?i:index;
}
printf("%d %d\n",index,ans);
}
return 0;
}
题目大意:
给定一颗树,对每个结点,其balance为去掉这个结点后产生的森林中各个子树的最大节点数,求所有节点中balance值最小的那个
解题思路:
设n为树中的结点总数,num[i]表示以结点i为根结点的子树的节点数
balance[k] = max(n-num[k],num[j1],num[j2]...num[jl])(j1,j2,...,jl是k的所有子树编号)
因为题目中给定的边的顺序未必是树的构建顺序,所以要用dfs+标记visit的方法来确定树中的根和子结点的关系