贪心套路 HNOI2003 消防局的设立/luogu 将军令

版权声明:未经本蒟蒻同意,请勿转载本蒻博客 https://blog.csdn.net/wddwjlss/article/details/82054665

给定一棵边权为1的树,控制一个点可以控制该节点和与该节点距离小于等于m的点,求最少控制多少个点可以控制一整棵树。
先以1号节点为根进行dfs,并求出每个点的深度。将这些点的深度和这些点的编号放入堆中,每次取出深度最大的节点,如果该节点已经被标记,则弹出该节点。否则对该节点的第m级祖先进行dfs(若该节点没有第m级祖先则对根节点1号节点进行dfs),将该节点第m级祖先和与该节点第m级祖先相距小于等于m的点标记,答案加一。

#include<bits/stdc++.h>
using namespace std;
int n,head[1001000],num,dep[1001000],f[1001000],ans,m,gg,x,fat;
bool book[1001000];
struct node
{
    int next,to;
}e[1001000];
priority_queue <pair<int,int> > q;
inline void add(int from,int to)
{
    e[++num].next=head[from];
    e[num].to=to;
    head[from]=num;
}
void dfs(int x,int fa)
{
    dep[x]=dep[fa]+1;
    f[x]=fa;
    for(register int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)
            continue;
        dfs(v,x);
    }
}
void dfs1(int x,int fa,int deep)
{
    if(deep>m)
        return;
    book[x]=1;
    for(register int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)
            continue;
        dfs1(v,x,deep+1);
    }
}
inline int read()
{
    char c=getchar();
    while(!isdigit(c))
        c=getchar();
    int x=c-48;
    for(c=getchar();isdigit(c);c=getchar())
        x=(x<<3)+(x<<1)+c-48;
    return x;
} 
int main()
{
    n=read();
    m=read();
    gg=read();
    for(int i=1;i<=n-1;++i)
    {
        int u,v;
        u=read();
        v=read();
        add(u,v);
        add(v,u);
    }
    dfs(1,0);
    for(register int i=1;i<=n;++i)
        q.push(make_pair(dep[i],i));
    while(!q.empty())
    {
        while(book[x=q.top().second]==1&&!q.empty())
            q.pop();
        if(q.empty())
            break;
        fat=x;
        for(register int i=1;i<=m;++i)
            fat=f[fat];
        if(fat)
            dfs1(fat,fat,0);
        else
            dfs1(1,0,0);
        ++ans;
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wddwjlss/article/details/82054665