题意
你有一颗 个节点的有根树(以
号节点为根),求最少加入多少条边之后使得根节点(即
号节点)到这棵树上任意一点的距离不大于
。
分析
考虑一种贪心,如果一个节点 到根的距离大于
的话,那么我们就从根节点连一条边到
节点的父亲
。
来考虑正确性的证明,一个节点 到根的距离如果大于了
,那么只会有两种方式连边
直接连向
。
连向他的父亲节点
。
我们分两种情况讨论:
如果
的父亲节点
除了
以外还有别的子节点,那么连向父亲节点
也可以同时覆盖其他儿子。
如果
没有其他儿子,那么连向
可以使得根节点到
的距离也减小,虽然
可能满足距离小于等于
,但这样一定不劣。
所以我们只需要每次找最远的点并连接根节点和它的父亲就好了。树上解决就好了。
代码
#include<bits/stdc++.h>
#define ll long long
const int N=2e5+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;
int n,cnt;
int head[N],f[N];
bool vis[N];
struct node
{
int to,nxt;
}e[N<<1];
struct node1
{
int num,dep;
}p[N<<1];
inline int read()
{
register int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
int qpow(int a,int b)
{
int ans=1;
while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
return ans;
}
bool cmp(node1 a,node1 b)
{
return a.dep>b.dep;
}
void add(int u,int v)
{
e[++cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void bfs(int rt)
{
queue <int> q;
p[rt].dep=0;p[rt].num=rt;
q.push(rt);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nxt)
{
int y=e[i].to;
if(p[y].dep) continue;
p[y].dep=p[u].dep+1;p[y].num=y;
f[y]=u;
q.push(y);
if(p[y].dep<=2) vis[y]=1;
}
}
}
int main()
{
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
bfs(1);
sort(p+1,p+n+1,cmp);
int ans=0;
for(int i=1;i<=n;i++)
{
if(vis[p[i].num]) continue;
ans++;
int u=f[p[i].num];
vis[u]=1;
for(int j=head[u];j;j=e[j].nxt) vis[e[j].to]=1;
}
printf("%d\n",ans);
return 0;
}
/*
7
1 2
2 3
2 4
4 5
4 6
5 7
7
1 2
1 3
2 4
2 5
3 6
1 7
7
1 2
2 3
3 4
3 5
3 6
3 7
*/
京公网安备 11010502036488号