题意:求树上的一个点,删除该点后形成的众多树中,最大的树的大小最小。换句话说就是求树的重心。
思路:DP+DFS
定义状态:dp[a]表示 以a 为根节点的子树大小
然后一遍DPS,每次判断a的子树的各个dp值和n-dp[a]的值中的最大值,答案存最小的那个即可。因为存的是无向图,忘记边数乘2了,WA了两次。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=22222;
int dp[maxn];
struct node
{
int to;
int next;
};
node edge[maxn<<1];
int vis[maxn];
int head[maxn];
int ans;
int nore;
int n;
int edge_sz;
void init()
{
memset(head,-1,sizeof(head));
edge_sz=0;
ans=inf;
nore=1;
}
void addedge(int a,int b)
{
edge[edge_sz].to=b;
edge[edge_sz].next=head[a];
head[a]=edge_sz++;
}
void cal(int u,int p)//求重心
{
dp[u]=1;
int v;
int mx=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(v!=p)
{
cal(v,u);
dp[u]+=dp[v];
mx=max(mx,dp[v]);
}
}
mx=max(mx,n-dp[u]);
if(mx==ans)
{
if(u<nore)
{
nore=u;
}
}
if(mx<ans)
{
ans=mx;
nore=u;
}
}
void input()
{
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
}
int main()
{
// freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
init();
input();
cal(1,0);
printf("%d %d\n",nore,ans);
}
return 0;
}