額這題也挺水的。
題意:找樹上滿足去掉它之後,剩餘連通的結點塊中最大的那一塊最小的結點們。
思路:有 dp[u] = max(sum[v], n - sum[u]); v是u的子結點
代碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e4 + 10,maxe = maxn * 2;
const int inf = 0x3f3f3f3f;
struct node
{
int to,next;
node(){}
node(int a,int b){to = a ; next = b;}
}edge[maxe];
int h[maxn],sum[maxn];
int num,n,anum;
int ans[maxn];int vans = inf;
void init()
{
for(int i = 0; i <= n; i++)
h[i] = -1, sum[i] = 0;
num = 0; anum = 0; vans = inf;
}
void add(int u,int v)
{
edge[num] = node(v,h[u]);
h[u] = num++;
}
void solve(int u,int pre)
{
int res = 0,cnt = 0;
for(int i = h[u] ;~i ; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre) continue;
solve(v,u);
cnt += sum[v];
res = max(sum[v],res);
}
sum[u] = cnt + 1;
res = max(res,n-sum[u]);
if(res < vans)
{
anum = 0;
vans = res;
ans[anum++] = u;
}
else if(res == vans)
ans[anum++] = u;
}
int main()
{
while(~scanf("%d",&n))
{
init();
int a,b;
for(int i = 0; i < n-1; i++)
{
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
solve(1,-1);
sort(ans,ans+anum);
for(int i = 0; i < anum; i++)
i==0?printf("%d",ans[i]) : printf(" %d",ans[i]);
printf("\n");
}
return 0;
}