zoukankan      html  css  js  c++  java
  • <JZOJ5944>信标

    emmm树形dp?好像是的

    搬一个题解证明过来

    由于在n>1时答案至少为1,我们枚举一个必须放的根, 所有深度不同的点就被区分开了.

    设一个节点有c个儿子, 发现必须在其中至少c−1个儿子的子树中放置信标.

    证明如下: 考虑如果不这样放, 对于两棵都没有放的子树, 他们汇集到lca上以后距离都是相等的, 所以lca外的信标无法区分, 而内部没有信标. 所以不能存在两颗子树都不放. 所以至少要放c-1个. 由于在根节点放置了信标, 可以只考虑深度相同的点. 由于深度相同, 所以他们的lca度数至少为2,那么一定有一个信标在lca包含这两个点的两支子树中. 那么另一侧的点肯定要走更远的路, 会被区分开. 所以放c−1个足够区分.

    这样问题变成每个节点要有c−1棵子树放有信标, 求最小方案. 直接贪心即可.

    由于枚举根所 以复杂度为O(n2), 可以获得70分.

    如何做到O(n)?

    我们先特判链的情况答案为1,然后找到任意一个度数大于2的节点,可以证明这个点一定不需要放置信标. 于是以这个点作根O(n)的贪心即可.

    证明如下:

    深度相同的点对证明同上,只考虑深度不同的点对.如果它们在一颗子树中,由于度数大于2所以一定有另一颗子树的一个信标把他们区分开.

    如果在不同的子树中, 有两种情况:

    一个在没放信标的子树中,一个在放了的子树中.显然还存在另一个子树放了信标,由于深度不同他们会被这个信标区分开.

    两个都在放了信标的子树中. 如果根的度数大于3则同上. 度数等于3时, 如果他们没有被区分开,一定是他们先汇集到了一个节点上, 然后走到同一个信标上. 这个点一定是一条奇链的中点, 且 不是根 (由于深度不同), 是在两个子树之一中唯一的. 那么他们走到另一个信标就一定有一个点走 了冤枉路, 既另一个信标可以区分出他们.

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define rint register int
    template <class T>inline void read(T &X)
    {
        X=0;int W=0;char ch=0;
        while(!isdigit(ch))W|=ch=='-',ch=getchar();
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        X=W?-X:X;return;
    }
    int n,head[1000010],cnt=0,count[1000010],f[1000010];
    struct node{int to,next;}edge[2000010];
    
    void add(int u,int v)
    {
        edge[++cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt;
    }
    
    void dfs(int now,int fa)
    {
        int num=0,tot=0;
        for(rint i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(to==fa)continue;
            dfs(to,now);
            tot+=f[to];
            if(!f[to])num++;
        }
        f[now]=tot;
        if(num>1)f[now]+=(num-1);
        return;
    }
    int main()
    {
        //freopen("beacon.in","r",stdin);
        //freopen("beacon.out","w",stdout);
        read(n);
        if(n==1){printf("0
    ");return 0;}
        for(rint i=1;i<n;++i)
        {
            int u,v;
            read(u),read(v);
            add(u,v),add(v,u);
            ++count[u],++count[v];
        }
        int sta=-1;
        for(rint i=1;i<=n;++i)if(count[i]>=3)sta=i;
        if(sta==-1){printf("1
    ");return 0;}
        dfs(sta,-1);
        printf("%d
    ",f[sta]);
    return 0;
    }
  • 相关阅读:
    win10安装jmeter配置环境路径
    genymotion在mac上的安装
    jmeter的启动
    win10的cmd输入javac的问题
    01 | 你真的懂测试吗?从“用户登录”测试谈起 茹炳晟
    冒烟测试
    软件测试基础知识
    红队指南--第3章 列举
    REDTEAM 指南---第四章 外部侦察
    Red Team 指南-第1章 红队和红队概述
  • 原文地址:https://www.cnblogs.com/pile8852/p/9892325.html
Copyright © 2011-2022 走看看