贪心【CF1029E】Tree with Small Distances

Description

给定一棵树。要求往树中加入一些边使得从1到其他节点的距离至多是2 。 输出加入边的最小数量。(边全部都是无向的)

Input

第一行一个整数n,表示树中的节点个数。 接下来n−1行,每行两个整数x,y,表示x,y之间有一条连边。

Output

输出一个整数,表示加入边的最小数量。

贪心做法,

我们每次选择深度最深的点,向其父节点加边来标记其他点。(到达这些点的距离都不超过\(2\).)

为什么向其父亲节点加边?因为这样会覆盖比较多的点。

如果遇到被标记的点,就\(continue\).

不太会证明正确性,但是可行。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
#define R register

using namespace std;

const int gz=2e5+8;

inline void in(R int &x)
{
    R int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}

int head[gz],tot,depth[gz],ans,n,f[gz],cnt;

bool ok[gz];

struct cod{int u,v;}edge[gz<<1];

inline void add(R int x,R int y)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}

struct hop
{
    int u,dep;
    bool operator <(const hop&a)const
    {
        return dep>a.dep;
    }
}q[gz];


void dfs(R int u,R int fa)
{
    depth[u]=depth[fa]+1;f[u]=fa;
    if(depth[u]>2)q[++cnt].u=u,q[cnt].dep=depth[u];
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v==fa)continue;
        dfs(edge[i].v,u);
    }
}

int main()
{
    in(n);
    for(R int i=1,x,y;i<n;i++)
    {
        in(x),in(y);
        add(x,y),add(y,x);
    }
    depth[0]=-1;
    dfs(1,0);
    sort(q+1,q+cnt+1);
    for(R int j=1;j<=cnt;j++)
    {
        R int u=q[j].u;
        if(ok[u])continue;
        u=f[u];
        ok[u]=true;
        for(R int i=head[u];i;i=edge[i].u)
            ok[edge[i].v]=true;
        ans++;
    }
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/-guz/p/9927049.html