牛客网暑期ACM多校第二场H - 树形DP

题目链接:点击这里

解题思路:

dp[i][0][j] 表示以i为根节点j条不相交路径的最大和

dp[i][1][j] 表示以i为根节点j条+1条一个端点在i的不相交路径的最大和

dp[i][0][j]的转移:

1.儿子的j条不相交路径的最大和

2.儿子的j-1条+2条端点在i的不相交路径

两者取最大即可

dp[i][1][j]的转移:

儿子的j条+1条端点在i的不相交路径

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
const int mx = 4e5 + 10;
typedef long long ll;
const int mod = 998244353;
int n,m,a[mx],tot,head[mx];
ll dp[mx][3][4];
struct node
{
	int y,nxt;
}edge[mx<<1];
void AddEdge(int x,int y)
{
	edge[tot] = {y,head[x]};
	head[x] = tot++;
}
void dfs(int x,int fa)
{
	ll tem[2][4][4];
	memset(tem,0,sizeof(tem));
	int id = 0;
	for(int i=head[x];~i;i=edge[i].nxt)
	{
		int v = edge[i].y;
		if(v==fa) continue;
		dfs(v,x);
		for(int i=0;i<=2;i++){
			for(int j=0;i+j<=2;j++){
				for(int p=0;p<=3;p++){
					for(int q=0;q+p<=3;q++){
						tem[id][i+j][p+q] = max(tem[id][i+j][p+q],tem[id^1][i][p]+dp[v][j][q]);
					}
				}
			}
		}
		id ^= 1;
	}
	for(int i=1;i<=3;i++) dp[x][0][i] = max(dp[x][0][i],tem[id^1][0][i]);
	for(int i=1;i<=3;i++) dp[x][0][i] = max(dp[x][0][i],tem[id^1][2][i-1]+a[x]);
	for(int i=0;i<=3;i++) dp[x][1][i] = max(dp[x][1][i],tem[id^1][1][i]+a[x]); 
} 
int main()
{
	while(~scanf("%d",&n))
	{
		int x,y;
		memset(head,-1,sizeof(head));
		tot = 0;
		for(int i=1;i<=n;i++) scanf("%d",a+i);
		for(int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			AddEdge(x,y);
			AddEdge(y,x);
		}
		dfs(1,0);
		printf("%lld\n",dp[1][0][3]);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/81415479
今日推荐