解析
题意是说依次删除一个点后存一下剩余的连通块的最大值,在这些最大值中求一个最小值。
题意模拟
样例图如下所示:
我们先删除根节点,此时有3个连通块,其中连通块中节点个数最多的是以4为根节点的子树的连通块,节点个数是4,所有根节点1的权重就是4:
接下来我们删除节点2,此时还剩两个连通块,其中连通块中节点个数最多的是以节点1为根节点的连通块,节点个数为6,所以节点2的权重就是6。
就这样枚举下去,然后求每个节点中权重最小的那个。
思路
问题就在于怎么求一个连通块内的个数。
我们知道数是向下遍历的,假设我们在节点4这个位置,我们只需要算上节点4本身这个节点个数,然后向下遍历节点4的子树,统计子树中节点的个数,一直遍历到空为止,此时向上返回统计的节点的个数,这个时候节点4存的就是以节点4为根的这个连通块中的节点的个数了,我们用size4表示:
此时,我们知道了以节点4为根节点的这个连通块的数量,那么不包含节点4的连通块中节点个数就等于n-size4:
code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = N * 2;
int n;
int h[N]; //头节点
int e[M]; //边值
int ne[M]; //next指针
int idx; //地址
bool st[N];
int ans = N; //ans存所有最大值中的最小值
//在a这个节点插入b这个边
void add(int a,int b)
{
e[idx] = b; //把b赋值给当前边值
ne[idx] = h[a]; //指向下一个节点
h[a] = idx++; //头指针移动
}
int dfs(int u)
{
st[u] = true; //标记为走过
int sum = 1, res = 0; //res存连通块节点个数的最大值
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; //以某个节点为根节点的1连通块要把1这个节点自身也算上
}
}
res = max(res,n-sum);
ans = min(ans,res);
return sum;
}
int main()
{
cin >> n ;
memset(h,-1,sizeof h); //头节点初始化
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;
}