这道题目的题意有点绕,就是说,一棵树,然后去点每一个点都找到他们剩下连通块中点数最大的,然后在这些最大的里面找到最小的那个,那个去掉的点就是树的中心。换句人话就是最大的里面最小的。
首先写一下主函数以及用链表的形式存储这棵树
//可以用dfs来做这样的题目,因为dfs是深度搜索,一条路走到黑的,我们可以给dfs定义一个返回值,返回值表示的就是这个点以及它的子节点的总数是多少
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+10,M=2*N;
int e[M],ne[M],idx,h[N];//e存被指向的那个节点,ne指向下一个被指向的节点,h是头节点
bool st[N];//用来记录有没有被搜索到
int ans=N;//因为要找到最小所以设计初值为N
int n;
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n;
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(1);
cout<<ans<<endl;
return 0;
}
那么我们怎么来找到每个点去掉后的最大连通图呢,去掉一个点后,一般有三个连同的树,分别为它的左右子树,以及它的父树。我们可以先将它的左右子树进行比较,找出其中较大的,然后加上它自身1记作sum,然后用n也就是总数减去sum就是它的父树中点的个数。
这样我们设计dfs的时候给其设置一个返回值,这个返回值就是包括那个点本身的子树的点的数量
int dfs(int u)
{
st[u]=true;//说明u这个点已经被搜索到了
int sum=1,res=0;//定义sum代表其包括其子树的总数,res代表删去这个点,所剩余的连通图中最大的点数
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
int t=dfs(j);//深度寻找,直至找到最后一个节点
res=max(res,t);//比较左右子树的一个步骤如果有的话,因为for循环会找到左右子树
sum+=t;//记录包括其自己的总数当然要加上左右子树
}
}
res=max(res,n-sum);//选出来的较大的左右子树与其父树的个数进行比较
ans=min(ans,res);//最大里面选最小的
return sum;//最后返回包括u号点+其子树的个数,返回给上层统计
}