codeforces 633F The Chocolate Spree (树形dp)

题目链接:http://codeforces.com/problemset/problem/633/F

题解:看起来很像是树形dp其实就是单纯的树上递归,就是挺难想到的。

显然要求最优解肯定是取最大的两条链不妨设dp[i][3],dp[i][1]表示以i为根节点的子树val最大的子链,dp[i][2]表示以i为根节点的子树val最大的两条子链。

显然dp[i][2]=max(dp[i][2],dp[i][1]+dp[v][1]) (v  表示i的子节点)

dp[i][2]=max(dp[i][2],down[i]+mmp[v]) (down[i]表示的是以i为根节点到子叶val最大的,mmp[v]表示以v为根节点的到子也最大值再加上一条最大的链的值)

dp[i][2]=max(dp[i][2],down[v]+mmp[i])

其实这些都是挺形象的几种可能性画一下图就知道了。

剩下的down的转移和mmp的转移具体看一下代码。这里还会涉及到一个bs[i]表示以dp[v][1]的最大值。

然后这些东西都通过递归dfs就行了。dfs是个神奇的东西

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int M = 1e5 + 10;
int a[M];
vector<int> vc[M];
ll dp[M][3] , down[M] , mmp[M] , bs[M];
void dfs(int u , int pre) {
    int len = vc[u].size();
    dp[u][1] = a[u];
    dp[u][2] = a[u];
    down[u] = a[u];
    bs[u] = 0;
    mmp[u] = a[u];
    for(int i = 0 ; i < len ; i++) {
        int v = vc[u][i];
        if(v == pre) continue;
        dfs(v , u);
        /////
        dp[u][2] = max(dp[u][2] , dp[v][2]);
        dp[u][2] = max(dp[u][2] , dp[u][1] + dp[v][1]);
        dp[u][2] = max(dp[u][2] , down[u] + mmp[v]);
        dp[u][2] = max(dp[u][2] , down[v] + mmp[u]);
        /////
        dp[u][1] = max(dp[u][1] , dp[v][1]);
        dp[u][1] = max(dp[u][1] , down[v] + down[u]);
        /////
        mmp[u] = max(mmp[u] , mmp[v] + a[u]);
        mmp[u] = max(mmp[u] , dp[v][1] + down[u]);
        mmp[u] = max(mmp[u] , down[v] + bs[u] + a[u]);
        /////
        bs[u] = max(bs[u] , dp[v][1]);
        /////
        down[u] = max(down[u] , down[v] + a[u]);
    }
}
int main() {
    int n;
    scanf("%d" , &n);
    for(int i = 1 ; i <= n ; i++) {
        scanf("%d" , &a[i]);
    }
    for(int i = 1 ; i < n ; i++) {
        int u , v;
        scanf("%d%d" , &u , &v);
        vc[u].push_back(v);
        vc[v].push_back(u);
    }
    dfs(1 , 0);
    printf("%lld
" , dp[1][2]);
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/7754108.html