SGU 134 Centroid
题目
题目大意
给定一棵有 个节点的无根树,求树的所有重心及以重心为根的最大子树的节点数量。
思路
很明显的一个DP版题。
所谓重心,就是指一棵树中,若将某个节点删除,得到的所有子树的节点数量尽可能的相等,则称该节点为重心。
基于这个思想,我们设 为以 为根的最大子树节点个数。
易得状态转移方程:
由于是树形结构,故直接使用DFS求出所有 ,答案即为
实现细节
注意:可能有多个重心,请按从小到大的顺序输出。
正解代码
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int Maxn=16000;
vector<int> G[Maxn+5];
void AddEdge(int u,int v) {
G[u].push_back(v);
G[v].push_back(u);
}
int N,K=1e9;
vector<int> t;
int dp[Maxn+5];
int DFS(int u,int fa) {
dp[u]=0;
int res=0,sum=0;
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa)continue;
int tmp=DFS(v,u);
res=max(res,tmp);
sum+=tmp;
}
dp[u]=max(res,N-sum-1);
return sum+1;
}
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d",&N);
for(int i=1;i<N;i++) {
int u,v;
scanf("%d %d",&u,&v);
AddEdge(u,v);
}
DFS(1,-1);
for(int i=1;i<=N;i++)
K=min(K,dp[i]);
for(int i=1;i<=N;i++)
if(dp[i]==K)
t.push_back(i);
printf("%d %d\n",K,t.size());
for(int i=0;i<t.size();i++)
printf("%d ",t[i]);
return 0;
}