给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的.
首先要知道什么是树的重心,树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重
心后,生成的多棵树尽可能平衡. 实际上树的重心在树的点分治中有重要的作用, 可以避免N^2的极端复杂度(从退化链的一端出发)
算法就是跑一遍dfs,找到最优解。
代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 20005; const int INF = 1<<30; int head[N]; int son[N]; bool vis[N]; int cnt,n; int ans,size; struct Edge { int to; int next; }; Edge edge[2*N]; void Init() { cnt = 0; size = INF; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void dfs(int cur) { vis[cur] = 1; son[cur] = 0; int tmp = 0; for(int i=head[cur]; ~i; i=edge[i].next) { int u = edge[i].to; cout<<u<<endl; if(!vis[u]) { dfs(u); son[cur] += son[u] + 1; tmp = max(tmp,son[u] + 1); } } tmp = max(tmp,n-son[cur]-1); if(tmp < size || tmp == size && cur < ans) { ans = cur; size = tmp; } } int main() { int T; scanf("%d",&T); while(T--) { Init(); scanf("%d",&n); for(int i=1; i<=n-1; i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); printf("%d %d\n",ans,size); } return 0; }
原文地址:https://www.cnblogs.com/DukeLv/p/9457881.html
时间: 2024-11-05 12:30:20