• P2607 [ZJOI2008] 骑士


    P2607 [ZJOI2008] 骑士

    [P2607 ZJOI2008] 骑士 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    题目大意

    给你一个 n n n 个点, n n n 条边的基环树森林。

    你可以从中选择若干个点,满足两两之间不存在边相连。

    每个点有一个权值,请问最大的权值和是多少。

    思路

    对于每棵基环树,记录返祖边连接的两个点 x , y x , y x,y

    d p x , 0 / 1 dp_{x , 0/1} dpx,0/1 表示点 x x x 选、不选时,以 x x x 为根的子树最大权值和是多少。

    显然
    d p x , 0 = ∑ y ∈ s o n ( x ) max ⁡ { d p y , 0 , d p y , 1 } d p x , 1 = ∑ y ∈ s o n ( x ) d p y , 0 dp_{x , 0} = \sum_{y \in son(x)} \max \{dp_{y , 0} , dp_{y , 1}\} \newline dp_{x , 1} = \sum_{y \in son(x)} dp_{y , 0} dpx,0=yson(x)max{dpy,0,dpy,1}dpx,1=yson(x)dpy,0
    因为 x , y x , y x,y 最多只能有一个选,所以没棵基环树的答案为 max ⁡ { d p x , 0 , d p y , 0 } \max \{dp_{x , 0} , dp_{y , 0}\} max{dpx,0,dpy,0}

    把全部基环树的答案加起来就好了

    不知道为什么 c++17 开了 O 2 O_2 O2 就 T 了。

    code

    #include 
    #define fu(x , y , z) for(int x = y ; x <= z ; x ++)
    #define LL long long
    using namespace std;
    const int N = 1e6 + 5;
    int n , vis[N] , cnt = 1 , hd[N] , pos , to , flgy;
    LL a[N] , dp[N][2] , ans;
    struct E {
        int to , nt;
    } e[N << 1];
    void add (int x , int y) { e[++cnt].to = y , e[cnt].nt = hd[x] , hd[x] = cnt; }
    void dfs1 (int x , int fa) {
        int y;
        vis[x] = 1;
        for (int i = hd[x] ; i ; i = e[i].nt) {
            y = e[i].to;
            if (y == fa) continue;
            if (!vis[y])
                dfs1 (y , x);
            else 
                pos = i;
        }
    }
    LL dfs (int x , int fa) {
        int y;
        dp[x][0] = 0;
        dp[x][1] = a[x];
        for (int i = hd[x] ; i ; i = e[i].nt) {
            y = e[i].to;
            if (y == fa || i == pos || i == (pos ^ 1)) continue;
            dfs (y , x);
            dp[x][0] += max (dp[y][0] , dp[y][1]);
            dp[x][1] += dp[y][0];
        }
    }
    int main () {
        int x , y;
        scanf ("%d" , &n);
        fu (i , 1 , n) {
            scanf ("%lld%d" , &a[i] , &x);
            add (i , x) , add (x , i);
        }
        LL ans1;
        fu (i , 1 , n) {
            if (vis[i]) continue;
            dfs1 (i , 0);
            x = e[pos].to , y = e[pos ^ 1].to;
            dfs (x , 0);
            ans1 = dp[x][0];
            dfs (y , 0);
            ans += max (ans1 , dp[y][0]);
        }
        printf ("%lld" , ans);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    运动捕捉系统原理
    强化学习中这种loss图正常吗
    Redis实现消息队列
    XenServer 控制台和图形化安装Centos6
    数据驱动的瑞幸咖啡未来会能赚!
    how2heap2.31学习(2)
    麒麟v10操作系统 安装docker
    算法金 | 秒懂 AI - 深度学习五大模型:RNN、CNN、Transformer、BERT、GPT 简介
    QT 实现16进制与字符串互转
    华为数通方向HCIP-DataCom H12-831题库(单选题:261-280)
  • 原文地址:https://blog.csdn.net/fzyyyyyyyy/article/details/133848537