题目:
给定一颗树,树中包含 nn 个结点(编号 1∼n1∼n)和 n−1n−1 条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数 nn,表示树的结点数。
接下来 n−1n−1 行,每行包含两个整数 aa 和 bb,表示点 aa 和点 bb 之间存在一条边。
输出格式
输出一个整数 mm,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1≤n≤105
数组建立邻接表
//邻接表
int h[N], e[N * 2], ne[N * 2], idx;//h:数组下标为此链表头节点的值,数组的值为此头节点的其中一个儿子节点的索引 e:此索引(数组下标)对应的节点值 ne:索引(数组下标)在链表中next节点的索引 idx:索引
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
dfs模板
void dfs(int u)
{
st[u] = true; //记录是否被搜索
for (int i = h[u]; i != -1; i = ne[i]) //遍历u节点的每个儿子节点
{
int j = e[i];
if (!st[j])
{
dfs(j);
}
}
}
题解
每个点当作重心时,子树的根为此节点的所有儿子节点以及一个父节点
res表示每个子树的节点数最大值
n-sum为u节点的父节点为根的子树的点数
dfs(u)=sum=u为根的子树节点数
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<queue>
#include<cstring>
using namespace std;
const int N = 100010, M = N * 2;
int n;
int h[N],e[M],ne[M],idx;
int ans=N;
bool st[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)//u为根的子树中 点数的数量
{
st[u]=true;
int res=0;//最大联通子图节点数
int sum=1;//dfs值
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
int s=dfs(j);
res=max(res,s);
sum+=s;
}
}
res=max(res,n-sum);
ans=min(ans,res);
return sum;
}
int main()
{
scanf("%d",&n);
memset(h,-1,sizeof h);
for(int i=0;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1);
printf("%d",ans);
return 0;
}