【DP】【贪心】[51Nod1378] 夹克老爷的愤怒

Description

给出N个点的一棵树,边的长度为1
你可以选择在某些上放一个家丁,一个家丁可以控制与此处距离不超过K的所有点。
求最小放置家丁数
N , K 10 5

Solution

如果是一条链的话,我们很容易想到从底向上贪心,每次当最深的点到当前点为K了就放一个
就是使放的点尽量向上

回到原来的问题
同样的,设 F [ i ] 表示当前以i为根的子树中,最近的家丁的距离
如果F[i]为负,则是最远的还没有被控制的点的距离

DFS回溯的时候讨论转移一下即可

Code

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
using namespace std;
int f[N],fs[N],nt[2*N],dt[2*N],n,m,l,ans;
void link(int x,int y)
{
    nt[++m]=fs[x];
    dt[fs[x]=m]=y;
}
void dfs(int k,int fa)
{
    int mi=-1,mx=-1;
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p!=fa)
        {
            dfs(p,k);
            mi=min(mi,f[p]-1);
            mx=max(mx,f[p]-1);
        }
    }
    if(mx>=abs(mi)-1&&mx>=0) f[k]=mx;
    else 
    {
        if(mi+1==-l) f[k]=l,ans++;
        else f[k]=mi;
    } 
}
int main()
{
    cin>>n>>l;
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        x++,y++;
        link(x,y),link(y,x);
    }
    if(l==0) printf("%d\n",n);
    else 
    {
        dfs(1,0);
        if(f[1]<0) ans++;
        printf("%d\n",ans); 
    }
}

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/80457556