• BZOJ 4726 POI 2017 Sabota? 树形DP


    4726: [POI2017]Sabota?

    Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special Judge
    Submit: 128  Solved: 49
    [Submit][Status][Discuss]

    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。

    Source

    鸣谢Claris上传

    Solution

    考虑不满足条件的情况,肯定是叶节点中出现了叛徒,然后不断往上传染。

    考虑树形DP,f[i]为i节点不变成叛徒的最小的比例,当i为叶节点时,f[i] = 1.0。

    转移:f[i] = max{f[i], min(f[son[i]], 1.0*siz[son[i]]/(son[i]-1))};

    其儿子不变成叛徒的最小比例为x,小于x,则其儿子会变成叛徒;其儿子所占的比例为y,小于y,则其儿子变成叛徒后会影响到它。

    故取p = min(x,y),小于p,则它会变成叛徒。取max{p},是为了让它的所有儿子都不影响到它。

    答案就是所有子树大小大于k的f[i]的max值。

    且需要注意,一开始只有一个叛徒,也就是说传染最多只会传染完某一棵子树。

    Code

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 5e5+10;
     6 const double EPS = 1e-8;
     7 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
     8 #define REP_EDGE(i, a) for (int i = (a); i != -1; i = e[i].nxt)
     9 #define mset(a, b) memset(a, b, sizeof(a))
    10 int fcmp(double x) { if (x > -EPS && x < EPS) return 0; return x < -EPS ? -1 : 1; }
    11 double max_(const double &AI, const double &BI) { return fcmp(AI-BI) == 1 ? AI : BI; }
    12 double min_(const double &AI, const double &BI) { return fcmp(AI-BI) == -1 ? AI : BI; }
    13 int n, k;
    14 struct Edge
    15 {
    16     int v, nxt;
    17     Edge (int v = 0, int nxt = 0): v(v), nxt(nxt) {}
    18 }e[maxn];
    19 int head[maxn], label, siz[maxn];
    20 double f[maxn];
    21 
    22 void ins(int u, int v) { e[++label] = Edge(v, head[u]), head[u] = label; }
    23 
    24 void dfs(int u, int fa)
    25 {
    26     siz[u] = 1;
    27     REP_EDGE(i, head[u])
    28         if (e[i].v != fa)
    29             dfs(e[i].v, u), siz[u] += siz[e[i].v];
    30     if (siz[u] == 1) { f[u] = 1.0; return ; }
    31     f[u] = 0.0;
    32     REP_EDGE(i, head[u])
    33         if (e[i].v != fa)
    34             f[u] = max_(f[u], min_(1.0*siz[e[i].v]/double(siz[u]-1), f[e[i].v]));
    35 }
    36 
    37 int main()
    38 {
    39     scanf("%d %d", &n, &k);
    40     REP(i, 1, n) head[i] = -1;
    41     label = -1;
    42     REP(i, 2, n){ int u; scanf("%d", &u), ins(u, i); }
    43     dfs(1, 0);
    44     double ans = 0.0;
    45     REP(i, 1, n)
    46         if (siz[i] > k) ans = max_(ans, f[i]);
    47     printf("%.8lf
    ", ans);
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    09-JS的事件流的概念(重点)
    08-jQuery的位置信息
    07-小米导航案例
    python-selector模块
    python--day9--异步IO、数据库、队列、缓存
    python--select多路复用socket
    python--gevent高并发socket
    python--协程
    python--进程锁、进程池
    python--多进程
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6594372.html
Copyright © 2020-2023  润新知