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

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825598.html


    题目描述

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

    输入

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

    输出

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

    样例输入

    9 3
    1
    1
    2
    2
    2
    3
    7
    3

    样例输出

    0.6666666667


    题解

    坑死人的树形dp

    首先易知叛徒一定为某棵子树。

    设f[i]表示使f[i]不为叛徒的最小x值。

    那么叶子结点的f[i]应该为1,实际上为比1多一点但无限接近1的数。

    对于非叶子节点,它不为叛徒的前提为所有子树都不能使该节点叛变。

    使该节点叛变需要满足2个条件:子树叛变、子树所占比例大于x。

    这两个条件都满足,需要取min;同时要让i的所有子树都不满足条件,需要取max。

    然后答案为所有节点数超过k的子树的f值的最大值。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #define eps 1e-9
    using namespace std;
    int head[500010] , to[500010] , next[500010] , cnt , si[500010];
    double f[500010];
    void add(int x , int y)
    {
    	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
    }
    void dfs(int x)
    {
    	int i;
    	si[x] = 1;
    	for(i = head[x] ; i ; i = next[i]) dfs(to[i]) , si[x] += si[to[i]];
    	if(si[x] == 1) f[x] = 1;
    	for(i = head[x] ; i ; i = next[i]) f[x] = max(f[x] , min(f[to[i]] , (double)si[to[i]] / (si[x] - 1)));
    }
    int main()
    {
    	int n , k , x , i;
    	double ans = 0.0;
    	scanf("%d%d" , &n , &k);
    	for(i = 2 ; i <= n ; i ++ ) scanf("%d" , &x) , add(x , i);
    	dfs(1);
    	for(i = 1 ; i <= n ; i ++ ) if(si[i] > k) ans = max(ans , f[i]);
    	printf("%.8lf
    " , ans);
    	return 0;
    }

     

  • 相关阅读:
    MySQL总结二
    MySQL总结一
    Flink 流处理API之Join
    Flink 流处理API之二
    Flink 流处理API之一
    Flink ProcessFunction API
    Flink Window
    Spark性能优化
    BPM软件_K2百家讲坛 | 越秀地产:K2为房企数字化转型带来更多可能_全球领先的工作流引擎
    BPM软件_K2签约龙光地产,为集团实现“千亿目标”保驾护航_全业务流程管理专家
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6825598.html
Copyright © 2011-2022 走看看