Step1 Problem:
给你 n 个节点的一颗树,问你至少加几条边,使得节点 1 到其他点的距离不超过 2.
数据范围:
2 <= n <= 2e5.
Step2 Ideas:
只要是距离节点 1 超过 2 的点,我们必须加一条边,使其距离不超过 2.
贪心思路:我们看最深的节点,如果它距离节点 1 的距离超过 2,那么加边连接节点 1 到该点的父亲肯定是最优的。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
struct node
{
int id, dep;
bool operator < (const node &b) const {
return dep > b.dep;
}
};
vector<int> Map[N];
int fq[N], dep[N];
node a[N];
int cnt, vis[N];
void dfs(int u, int f, int step)
{
fq[u] = f;
dep[u] = step;
if(step >= 3) {
a[cnt++] = (node){u, step};
}
for(int i = 0; i < Map[u].size(); i++)
{
int to = Map[u][i];
if(to != f) dfs(to, u, step+1);
}
}
void add(int u, int v)
{
Map[u].push_back(v);
Map[v].push_back(u);
}
int main()
{
int n, u, v;
scanf("%d", &n);
for(int i = 1; i < n; i++)
{
scanf("%d %d", &u, &v);
add(u, v);
}
cnt = 0;
dfs(1, -1, 0);
sort(a, a + cnt);//所有需要加边的点,按深度从高到低排序
memset(vis, 0, sizeof(vis));
int ans = 0;
for(int i = 0; i < cnt; i++)
{
int id = a[i].id;
if(vis[id]) continue;
ans++;
if(fq[id] != -1) {
vis[fq[id]] = 1;
for(int i = 0; i < Map[fq[id]].size(); i++)
{
int to = Map[fq[id]][i];
vis[to] = 1;
}
}
else {//因为自己的儿子肯定已经通过加边,变得合法了。
vis[id] = 1;
}
}
printf("%d\n", ans);
return 0;
}