zoukankan      html  css  js  c++  java
  • Luogu P2279 [HNOI2003]消防局的设立

    这真的是一道SB题。去你的树形DP

    我们看到题目就开始考虑贪心,怎么搞?

    一个显然的思路,每次找出一个深度最大且未被覆盖的点,然后建一个消防局?

    但这样的话,动用简单的人类思维就可以知道:我TM的还不如放在它爷爷(父节点的父节点)处呢

    然后考虑有没有反例。。。。。。30min later

    怎么一个反例都没有?那么说明这个贪心是正确的了?

    接下来我们来简单证明一下贪心的正确性:

    由于这个点是当前深度最大且未被覆盖的点,因此所有深度比它深的点都被覆盖了。

    然后没有被覆盖且可以被这个点覆盖的点还有以下几类:

    1. 它自己(or 兄弟)
    2. 它的父亲节点
    3. 它的爷爷节点

    然后我们很容易发现,当把消防站设立在它爷爷处不仅可以覆盖到所有1,2,3情况的点,还可以多往上覆盖一些点。

    然后我们直接贪即可。由于这里我们可以通过BFS的顺序直接得出这些点的深度(这样就直接排好序了)

    最后一个一个弹出判断即可,复杂度(O(N))

    CODE

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    using namespace std;
    const int N=1005;
    struct edge
    {
        int to,next;
    }e[N<<1];
    int head[N],cnt,n,x,father[N],q[N],ans;
    bool vis[N];
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch; while (!isdigit(ch=tc()));
        while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline void double_add(int x,int y)
    {
        e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
        e[++cnt].to=x; e[cnt].next=head[y]; head[y]=cnt;
    }
    inline void BFS(int x)
    {
        register int i,H=0,T=1; q[1]=x; vis[x]=1;
        while (H<T)
        {
            int now=q[++H];
            for (i=head[now];~i;i=e[i].next)
            if (!vis[e[i].to]) q[++T]=e[i].to,vis[e[i].to]=1;
        }
    }
    inline void reset(int now,int d)
    {
        if (d>2) return; vis[now]=1;
        for (register int i=head[now];~i;i=e[i].next)
        reset(e[i].to,d+1);
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register int i; read(n);
        memset(head,-1,sizeof(head));
        for (i=2;i<=n;++i)
        read(x),double_add(i,x),father[i]=x; BFS(1);
        memset(vis,0,sizeof(vis)); father[1]=1;
        while (n) 
        {
            if (!vis[q[n]]) ++ans,reset(father[father[q[n]]],0); --n;
        }
        return printf("%d",ans),0;
    }
    
  • 相关阅读:
    一条痛并快乐的路
    Daily Scrum 11.1
    Daily Scrum 10.31
    Daily Scrum 10.30
    Daily Scrum 10.29
    Daily Scrum 10.28
    Daily Scrum 10.27
    (Alpha)Let's-Chronos分数分配规则
    Daily Scrum 10.26
    Daily Scrum 10.25
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9379173.html
Copyright © 2011-2022 走看看