CF633F The Chocolate Spree

CF633F The Chocolate Spree

洛谷传送门

题意翻译

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


题解:

树形DP好题。

众所周知,作为一道DP题,当你没办法转移的时候,你要想着再多来几个状态帮你转移。

比如这道题:

我们直接设答案:(dp[x][0])表示以x为根的子树选出两条不相交链的最大值。

怎么转移呢?

首先设当前节点为(x),其中一个儿子为(y)。转移要对以下四步取max:

首先,要在以(y)为根的子树中选两条不相交链,这可能是答案。然后,在(y)为根的子树中选一条,在其他儿子里选一条。再然后,从该点和子树中分别选出半条链,再从子树里选一条完整链。最后,第三条的反向思路也是可以的。

然后发现一时半会没办法维护这四种情况。于是再来几个状态:(dp[x][0])表示以(x)为根的子树选出一条链的最大值。(g[x])表示以(x)为根的子树中从(x)到叶子再加上一条不相交链的最大值。(down[x])表示从(x)到叶子节点的最大值。然后为了快速维护第二种情况,再加上(h[x])表示所有儿子的(dp[y][0])最大值。

大功告成,还有亿点点细节。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std; 
const int maxn=1e5+5;
const int INF=0x3f3f3f3f;
int n;
vector<int> e[maxn];
int w[maxn];
ll dp[maxn][2],g[maxn],h[maxn],down[maxn];
void dfs(int x, int f) 
{	
    dp[x][0]=dp[x][1]=g[x]=down[x]=w[x];
    h[x]=0;	
    for(int i=0;i<e[x].size();i++) 
    {	
    	int u=e[x][i];		
    	if(u==f) 
            continue;	
		dfs(u,x);			
    	dp[x][0] = max(dp[x][0], dp[u][0]);	
    	dp[x][0] = max(dp[x][0], dp[x][1]+dp[u][1]);	
		dp[x][0] = max(dp[x][0], down[x]+g[u]);		
        dp[x][0] = max(dp[x][0], g[x]+down[u]); 	
	    dp[x][1] = max(dp[x][1], dp[u][1]);	
	    dp[x][1] = max(dp[x][1], down[x]+down[u]); 	
	    g[x] = max(g[x], w[x]+g[u]);	
	    g[x] = max(g[x], down[x]+dp[u][1]);		
	    g[x] = max(g[x], down[u]+w[x]+h[x]); 
	    h[x] = max(h[x], dp[u][1]); 		
	    down[x] = max(down[x], down[u]+w[x]);	
    }
}
int main()
{    
	scanf("%d",&n);	
	for(int i=1;i<=n;i++)		
	    scanf("%d",&w[i]);	
	for(int i=1;i<n;i++) 
    {		
    	int u,v;		
    	scanf("%d%d",&u,&v);		
    	e[u].push_back(v);
        e[v].push_back(u);
    }	
	dfs(1,0);	
	printf("%lld",dp[1][0]);    
	return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/14037173.html