[洛谷P3942]将军令

题目大意:有n个驿站形成一棵树。一支小队在某个驿站驻扎时,可以控制与这个驿站距离不超过k的所有驿站(每条边长度算1)。问至少需要驻扎多少小队?

解题思路:贪心。要控制所有驿站,我们从最深的节点开始考虑。

要使一支小队控制到这个节点,又要让它贡献尽可能多,我们应该让它驻扎在当前节点的第k个祖先的节点上。

然后把所有已经被控制的节点打上标记。

接着从剩下的、没被打上标记的最深的节点考虑,继续如上方法贪心即可。

打标记的过程dfs一遍即可。

最后驻扎了几支小队,答案就是多少。

注意当一个节点没有第k个祖先(即它的某个祖先是根节点且不为第k个祖先),则直接让其驻扎在根节点上。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k,head[100005],cnt,fa[100005];
bool vis[100005];
struct edge{
    int to,nxt;
}e[200010];
struct Deep{
    int s,num;
    bool operator <(const Deep& rhs)const{return s>rhs.s;}
}dep[100005];
inline int readint(){
    char c=getchar();
    for(;!isdigit(c);c=getchar());
    int d=0;
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
void dfs(int now){
    for(int i=head[now];i;i=e[i].nxt)
    if(e[i].to!=fa[now]){
        fa[e[i].to]=now;
        dep[e[i].to]=(Deep){dep[now].s+1,e[i].to};
        dfs(e[i].to);
    }
}
void fg(int now,int p,int pre){
    vis[now]=true;
    if(k!=p++)
    for(int i=head[now];i;i=e[i].nxt)
    if(e[i].to!=pre)
    fg(e[i].to,p,now);
}
int main(){
    cnt=0;
    memset(dep,0,sizeof dep);
    memset(head,0,sizeof head);
    n=readint(),k=readint();readint();
    for(int i=1;i<n;++i){
        int u=readint(),v=readint();
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
        e[++cnt]=(edge){u,head[v]};
        head[v]=cnt;
    }
    fa[1]=1;
    dep[1]=(Deep){1,1};
    dfs(1);
    sort(dep+1,dep+n+1);
    memset(vis,0,sizeof vis);
    int ans=0;
    for(int i=1;i<=n;++i)
    if(!vis[dep[i].num]){
        int grf=dep[i].num;
        for(int j=1;j<=k;++j)grf=fa[grf];
        fg(grf,0,grf);
        ++ans;
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7776947.html