Description
给出一棵n个节点的无向树,问删去树上哪个顶点及与这个点相连的边后,能够最小化剩余连通块中节点的最大值
Input
第一行为一整数n表示点数,之后n-1行每行两个整数表示树上一条边(1<=n<=16000)
Output
输出删去一个顶点后最小的剩余剩余连通块中节点的最大值,并输出满足这个条件的节点数以及这些节点的编号
Sample Input
7
1 2
2 3
2 4
1 5
5 6
6 7
Sample Output
3 1
1
Solution
用树形DP统计以每个点为根的子树的节点数size[i]和每个点的子树中节点数最大值val[i],那么删去每个点后的答案值为val[i]=max(val[i],n-size[i]),之后从val数组中找最小值和最小值对应的i即可
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 22222
struct Edge
{
int to,next;
}edge[2*maxn];
int n,head[maxn],tot,size[maxn],val[maxn],ans[maxn],res;
void init()
{
tot=res=0;
memset(head,-1,sizeof(head));
memset(val,0,sizeof(val));
}
void add(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int fa)
{
size[u]=1;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa)continue;
dfs(v,u);
size[u]+=size[v];
val[u]=max(val[u],size[v]);
}
}
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
int m=n;
for(int i=1;i<=n;i++)
{
val[i]=max(val[i],n-size[i]);
if(val[i]<m)
m=val[i],res=0,ans[res++]=i;
else if(val[i]==m)ans[res++]=i;
}
printf("%d %d\n",m,res);
for(int i=0;i<res;i++)
printf("%d%c",ans[i],i==res-1?'\n':' ');
return 0;
}