zoukankan      html  css  js  c++  java
  • Luogu3554 [POI2013]LUK-Triumphal arch(二分答案+树形DP)题解

    题意补充

    • 事实上,(A)每次能染的(k)个节点并不一定与(B)所在节点相邻,换言之,(A)可以提前染一些节点使得(B)以后走不到。
    • 数据范围:(1 leq n leq 300000)

    算法

    二分答案 + 树形DP

    思路

    二分每次染的节点个数(k),再用树形DP检查;

    (f_u)为以(u)节点为根的子树(不含(u))全部染完除了(k)以外还需要的次数,那么:

    [f_u = max(sum{f_v} ; +siz_u - k, 0) ]

    其中,(siz_u)(u)的儿子数量。最后当(f_1 = 0)时即为合法。

    注意要从儿子往父亲推,这样才能避免不知道先处理哪一个儿子的情况。

    为什么贪心是错的:

    考虑这种情况:有一个节点有大量儿子,而它的兄弟节点们只有一个儿子,显然,贪心是不好处理的。

    参考代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 3e5 + 10;
    int n,head[maxn << 1],num;
    struct Edge{
        int then,to;
    }e[maxn << 1];
    
    void add(int u, int v){e[++num] = (Edge){head[u], v}; head[u] = num;}
    
    int f[maxn];
    void DFS(int u, int fa, int ch){
        int cnt = 0;
        for(int i = head[u]; i; i = e[i].then){
            int v = e[i].to;
            if(v != fa){
                cnt ++;
                DFS(v, u, ch);
                f[u] += f[v];
            }
        }
        f[u] = max(0, f[u] + cnt - ch);
    }
    
    int check(int p){
        memset(f,0,sizeof(f));
        DFS(1, 1, p);
        return (f[1] <= 0);
    }
    
    int main(){
        scanf("%d", &n);
        for(int i = 1; i < n; ++ i){
            int u,v; scanf("%d%d", &u, &v);
            add(u, v); add(v, u);
        }
        int l = 0, r = maxn;
        while(l <= r){
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid - 1;
            else l = mid + 1;
        }
        printf("%d
    ", r + 1);
        return 0;
    }
    

    福利数据

    7
    1 2
    1 3
    2 5
    2 6
    7 2
    4 1
    ans:3
    
  • 相关阅读:
    机器学习的几个知识点记录(转)
    mysql缓存、存储引擎
    特性选择、特征抽取阅读记录
    聚类、降维、文本处理阅读记录
    标准化、正则化阅读记录
    广播变量、累加器、collect
    实现Map-side Join和Reduce-side Join(转)
    MySQL数据库迁移(转)
    “数据迁移”考虑
    QT的信号和槽
  • 原文地址:https://www.cnblogs.com/whenc/p/13967446.html
Copyright © 2011-2022 走看看