gx巨巨的题意:
此题要求我们求一棵树的重心。
给定一棵N个结点的树,求该树的所有重心。重心的定义如下:
删掉某结点i后,若剩余k个连通分量,那么定义d(i)为这些连通分量中结点数的最大值。
所谓重心,就是使得d(i)最小的结点i。
算法分析:
建图;
树的基本操作:以结点1为根,计算出每个结点所在的子树的结点数。
枚举每一个结点,若将其删掉,那么考虑剩余的所有连通分量。
1、它的子树,其结点数可以直接调用。
2、它的上方子树,其结点数可通过n-1-减去所有子树的结点数算出。
这样,在其中选择d(i)最小的即可。时间复杂度:O(N),空间复杂度:O(N)
相当于树形dp
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}
#define N 20010
struct Edge{
int from, to, nex;
}edge[N<<1];
int head[N], edgenum;
void addedge(int u, int v){
Edge E = {u, v, head[u]};
edge[ edgenum ] = E;
head[u] = edgenum++;
}
int num[N], dp[N], n;
void dfs(int u, int fa){
num[u] = 1; dp[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nex){
int v = edge[i].to;
if(v == fa)continue;
dfs(v, u);
num[u] += num[v];
dp[u] = Max(dp[u], num[v]);
}
dp[u] = Max(dp[u], n - num[u]);
}
int main(){
int T, i;
scanf("%d",&T);
while(T--){
memset(head, -1, sizeof(head)); edgenum = 0;
scanf("%d",&n);
for(i = 1; i < n; i++)
{
int u, v;scanf("%d %d",&u,&v);
addedge(u, v);
addedge(v, u);
}
dfs(1, -1);
int minnum = N, pos;
for(i = 1; i <= n; i++)
if(minnum > dp[i])
{
minnum = dp[i];
pos = i;
}
printf("%d %d\n", pos, minnum);
}
return 0;
}