zoukankan      html  css  js  c++  java
  • 【BZOJ4726】[POI2017]Sabota? 树形DP

    【BZOJ4726】[POI2017]Sabota?

    Description

    某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
    下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
    成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
     

    Input

    第一行包含两个正整数n,k(1<=k<=n<=500000)。
    接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是p[i+1](1<=p[i+1]<=i)。

    Output

    输出一行一个实数x,误差在10^-6以内都被认为是正确的。

    Sample Input

    9 3
    1
    1
    2
    2
    2
    3
    7
    3

    Sample Output

    0.6666666667

    HINT

    答案中的x实际上是一个无限趋近于2/3但是小于2/3的数
    因为当x取2/3时,最坏情况下3,7,8,9都是叛徒,超过了k=3。

    题解:一眼看题就觉得是二分,后来发现二分根本没有必要,而且会TLE

    设f[i]表示无法使i的子树中所有人都变成叛徒的最小x,可以列出方程

    f[i]=max( f[i],min( f[j],siz[j]/( siz[i]-1 ) ) )   (j是i的儿子)

    也就是说,如果j的子树大小所占比例高于x,并且让j全变成叛徒需要的x比当前值大,都会使i也变成叛徒,所以f[i]必须必他们的最小值大才可以

    注意答案不是f[1],而是所有满足siz[i]>k的f[i]的最大值

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=500010;
    int n,cnt,m;
    double ans,f[maxn];
    int siz[maxn],to[maxn],next[maxn],head[maxn];
    void add(int a,int b)
    {
        to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x)
    {
        siz[x]=1;
        for(int i=head[x];i!=-1;i=next[i])  dfs(to[i]),siz[x]+=siz[to[i]];
        if(siz[x]==1)   f[x]=1.0;
        for(int i=head[x];i!=-1;i=next[i])
            f[x]=max(f[x],min(f[to[i]],1.0*siz[to[i]]/(siz[x]-1.0)));
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int i,a;
        memset(head,-1,sizeof(head));
        for(i=2;i<=n;i++)    scanf("%d",&a),add(a,i);
        dfs(1);
        for(i=1;i<=n;i++)    if(siz[i]>m) ans=max(ans,f[i]);
        printf("%.10f",ans);
        return 0;
    }
  • 相关阅读:
    如何快速把 Vue 项目升级到 webpack3
    10分钟学会ES7+ES8
    数组的32场演唱会
    你做的拷贝是真的深拷贝吗
    浅谈CSS模块化
    CORS跨域资源共享你该知道的事儿
    像VUE一样写微信小程序-深入研究wepy框架
    小型Web页打包优化(下)
    PT与PX区别
    px、pt和em的区别
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6819554.html
Copyright © 2011-2022 走看看