• 「Solution」CodeForces 633F The Chocolate Spree


    本题是华一高Ks 2020.11.26 T4 Attack

    (Description)

    给出一棵有(n)个节点的树,每个节点有一个权值(a_i),求出不相交的两条链的最大权值和。

    (2 leq n leq 10^5)

    (1 leq a_i leq 10^9)

    (Solution)

    一道树形DP好题,难点在于状态的转移,即两条链的形态。

    不要怕多设状态,重点在于把所有情况都描述出来。

    (DP_{now,0}: 最大两条链之和)
    (DP_{now,1}: 最大一条链)
    (DP_{now,2}: 到叶子节点的链+一条与之不相交的链最大值)
    (DP_{now,3}: 儿子节点DP_{x,1}最大值)
    (DP_{now,4}: 到叶子节点的最大链)

    对于每种转移,代码里有解释,建议在草稿纸上画图,对理解很有帮助。

    (AC space Code)

    仅展示代码的核心部分。

    Void dfs(int now, int fa){
        // 初始化
        dp[now][0] = dp[now][1] = dp[now][2] = dp[now][4] = a[now];
        dp[now][3] = 0;
    
        for(auto x: g[now]){
            if(x == fa) continue;
            dfs(x, now);
    
            /* ***************************************** *
            * dp[][0]: 最大两条链之和
            * dp[][1]: 最大一条链
            * dp[][2]: 到叶子节点的链+一条与之不相交的链最大值
            * dp[][3]: 儿子节点dp[][1]最大值
            * dp[][4]: 到叶子节点的最大链
            * ***************************************** */
    
            dp[now][0] = max(dp[now][0], dp[now][1] + dp[x][1]);           // 子树内最大一条链+子节点子树内最大一条链
            dp[now][0] = max(dp[now][0], dp[x][0]);                        // 从子节点直接转移
            dp[now][0] = max(dp[now][0], dp[x][2] + dp[now][4]);           // 子节点子树内到叶子节点的链 与 子树内到叶子节点的链构成一条穿过当前节点的链+一条与之不相交的链
            dp[now][0] = max(dp[now][0], dp[now][2] + dp[x][4]);           // 与上面的转移类似
    
            dp[now][1] = max(dp[now][1], dp[x][1]);                        // 从子节点直接转移
            dp[now][1] = max(dp[now][1], dp[now][4] + dp[x][4]);           // 子节点子树内到叶子节点的链 与 子树内到叶子节点的链构成一条穿过当前节点的链
    
            dp[now][2] = max(dp[now][2], dp[x][2] + a[now]);               // 从子节点直接转移,将子节点子树内那条到达叶子结点的链延伸到当前节点
            dp[now][2] = max(dp[now][2], dp[x][4] + dp[now][3] + a[now]);  // 与上面的转移类似
            dp[now][2] = max(dp[now][2], dp[now][4] + dp[x][1]);           // 按照dp[][2]的定义直接转移
    
            dp[now][3] = max(dp[now][3], dp[x][1]);                        // 按照dp[][3]的定义直接转移
    
            dp[now][4] = max(dp[now][4], dp[x][4] + a[now]);               // 按照dp[][4]的定义直接转移,将最大链延伸到当前节点
        }
    }
    int main(){
        input(n);
        for(ri i = 1; i <= n; i++) input(a[i]);
        for(ri i = 1; i < n; i++){
            input(u, v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, 0);
        write(dp[1][0]);
    	return 0;
    }
    
    • 最优解(Rank15)
    • 1.39s
    • 11.84MB
    • 2.40KB
  • 相关阅读:
    第五天
    第四天
    第三天
    四则运算2
    对于搜狗输入法
    用户及用户场景分析
    总结
    第一阶段总结
    第七天
    第六天
  • 原文地址:https://www.cnblogs.com/liuxizai/p/14047937.html
Copyright © 2020-2023  润新知