原题链接如下:
AcWing 846. 树的重心
详细题解分析可以看y总视频讲解:
视频题解
题目如下:
给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数 n,表示树的结点数。
接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。
输出格式
输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1≤n≤10^5
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
const int M = 2*N;//以有向图的形式存储无向图 所以每个节点至多对应2n-2条边
int n;//代表树的结点个数
int h[N];//邻接表存储树,有n个节点,所以需要n个头节点
int e[M];//存储元素
int ne[M];//存储列表的next值
int idx;//单链表指针
int ans = N;//由于ans是在每次更新的时候取更小的那个 所以我们初始值应该弄成尽可能大的 最大为N
bool st[N];//记录节点是否被访问过 dfs标配
//邻接矩阵的构造
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])
{
int j = e[i];
//如果这个节点没有被访问过
if(!st[u])
{
dfs(j);
}
}
}*/
//记录以u为根的子树的节点个数 包括u本身
int dfs(int u)
{
int sum = 1;
int res = 0;//存储 删掉某个节点之后,最大的连通图中含有的节点数
st[u] = true;//标记的访问过u节点
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;
}
}
//n-sum 如图中的n-size值,不包括根节点4;
res = max(res,n-sum);//选择u节点为重心,最大的 连通子图节点数
ans = min(ans,res);//遍历过的重心中,最小的最大连通图的节点数
return sum;
}
int main()
{
//初始化h数组
memset(h,-1,sizeof h);
cin>>n;
for(int i = 0;i<n-1;i++)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);//构造无向图
}
dfs(1);//可以选择从任意一个起点开始
cout<<ans<<endl;
return 0;
}