一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
题目
分析
问题:如何快速的求出来把每个点删掉后,最大值的最小者是多少?
- 在dfs中, 我们可以算出来每个子树的大小
- 以删掉4为例
数和图的DFS框架代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = N * 2;
int n, m;
int h[N], e[M], ne[M], idx; // e:存所有的结点的值; ne:存所有结点的next值是多少
bool st[N]; // 开一个bool数组存一下哪些点已经被遍历过了
int ans; // 最小的最大值,全局的答案
// 插入一条a指向b的边,也就是在a对应的邻接表的表头插入b
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u) // u表示当前已经dfs到的点
{
st[u] = true; // 标记一下当前这个点已经被搜过了
// 遍历一下u的所有出边
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j]) dfs(j); // 如果j没有别搜过的话,就一条路走到黑
}
}
int main()
{
memset(h, -1, sizeof h); // 链表的初始化,将所有的头全部初始化为-1即可
dfs(1); // 表示从第一点开始搜
}
本题代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = N * 2;
int n;
int h[N], e[M], ne[M], idx; // e:存所有的结点的值; ne:存所有结点的next值是多少
bool st[N]; // 开一个bool数组存一下哪些点已经被遍历过了
int ans = N; // 最小的最大值,全局的答案
// 插入一条a指向b的边,也就是在a对应的邻接表的表头插入b
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
// 返回以u为跟的子树里点的数量
int dfs(int u) // u表示当前已经dfs到的点
{
st[u] = true; // 标记一下当前这个点已经被搜过了
int sum = 1, res = 0;// sum:记录一下当前子树的大小 res:记录将该点删掉后,所有联通块中的最大值
// 遍历一下u的所有出边
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j])
{
// 如果j没有别搜过的话,就一条路走到黑
int s = dfs(j); // s表示当前子树的大小
res = max(res, s); // 因为当前子树也算一个联通块,所以也要跟res取一个max
sum += s;
}
}
// 当前子树的上面那坨(n - sum)也要算
res = max(res, n - sum);
ans = min(ans, res);
return sum;
}
int main()
{
cin >> n;
memset(h, -1, sizeof h); // 链表的初始化,将所有的头全部初始化为-1即可
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;
}