第一反应是先求出树的中心,然后再递归计算所有邻接点,返回最大值。
实际操作是先用函数dfs1求出树的重心(要用两次),然后bool数组里面把重心置true,再写个函数dfs2返回节点数
可是一看题目难度 简单 这种艰苦朴素的方法宣布破产
第二个想法是只dfs一遍,边遍历边记录,这个想法刚有雏形,突然感觉肚子痛,去厕所拉屎拉了15分钟,回来题意忘记了,此时重新读题,由于精疲力尽,恍惚之中把题意理解错了。
当时错误的理解是: 切掉树其中一条边,返回最大的子树的节点数。
由于题目给的是无向图,从上往下递归,递归中途父节点是没有值的(父节点知置为true的点,值=以该点为根的子树的节点数),当前节点的值无法和父节点作比较,想到这里,爷彻底晕了。
五秒钟之后,害,既然求切掉一条边后树的最大子树节点数,树n-1条边是正好连通的,直接返回n/2不就是最大节点么?想到这里我真是又气又晕,于是点开了y总的视频。
听完y总讲的题意解析,终于发现自己题意理解错了,赶忙抱起电脑屏幕对着y总的小脸连亲三大口。
因为删掉节点,不用考虑父节点,此时留下的分别是父节点的各子树,父节点的父节点的那棵爷爷树,这棵树可以用总结点n-∑子树节点 来算。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+10;
vector<int> son[N];
bool st[N];
int ans=1e9;
int n;
int dfs(int p)
{
st[p]=true;
int res=0,sum=0,temp;
for(auto i:son[p])
if(!st[i])
{
temp=dfs(i);
res=max(res,temp);
sum+=temp;
}
res=max(res,n-sum-1);
ans=min(ans,res);
return sum+1;
}
int main()
{
cin>>n;
for(int i=0;i<n-1;i++)
{
int a,b;cin>>a>>b;
son[a].push_back(b);
son[b].push_back(a);
}
dfs(1);
cout<<ans<<endl;
return 0;
}
标题牛逼