Description
给一颗n个结点的树,节点编号为1~n,问删除一个节点之后,让剩下的分支中节点数量最多的尽量少(可能有多种方案,按编号顺序输出)
Input
第一行为一个整数n表示节点数,之后n-1行每行两个整数a和b表示a节点与b节点之间有一条边
Output
按顺序输出满足条件的点
Sample Input
6
1 2
2 3
2 5
3 4
3 6
Sample Output
2 3
Solution
树形DP,用dp[i]表示删除i节点后剩下的分支中节点数最大值,首先dfs统计出每个节点子树的节点个数num[i],则有dp[u]=max(dp[u],n-num[u]),求出dp数组之后枚举每个点找出最小的节点数最大值,然后再枚举一遍找出满足节点数最大值最小的节点输出即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 55555
#define INF 0x3f3f3f3f
struct node
{
int to;
int next;
}edge[maxn*2];
int tol;
int head[maxn];
int dp[maxn];
int num[maxn];
int vis[maxn];
int ans[maxn];
int n;
void init()//初始化
{
tol=0;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
}
void add(int a,int b)//建边
{
edge[tol].to=b;
edge[tol].next=head[a];
head[a]=tol++;
}
int dfs(int u)//d统计每个节点子树的总节点数
{
vis[u]=1;
num[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v])
num[u]+=dfs(v);
}
return num[u];
}
void goto_dp(int u)
{
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v])
dp[u]=max(dp[u],n-num[u]);
else
{
dp[u]=max(dp[u],num[v]);
goto_dp(v);
}
}
}
int main()
{
while(~scanf("%d",&n))
{
init();//初始化
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs(1);//找出每个节点子树的总节点数
memset(vis,0,sizeof(vis));//初始化
goto_dp(1);
int minn=INF;
for(int i=1;i<=n;i++)//找出最小的节点数最大值
minn=min(minn,dp[i]);
int res=0;
for(int i=1;i<=n;i++)//找到满足条件的点
if(dp[i]==minn)
ans[res++]=i;
for(int i=0;i<res;i++)
printf("%d%c",ans[i],i==res-1?'\n':' ');
}
return 0;
}