题目链接: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; }