牛客网暑期ACM多校训练营(第二场)H travel

题目描述 
White Cloud has a tree with n nodes.The root is a node with number 1. Each node has a value.
White Rabbit wants to travel in the tree 3 times. In Each travel it will go through a path in the tree.
White Rabbit can't pass a node more than one time during the 3 travels. It wants to know the maximum sum value of all nodes it passes through.


输入描述:
The first line of input contains an integer n(3 <= n <= 400001)
In the next line there are n integers in range [0,1000000] denoting the value of each node.
For the next n-1 lines, each line contains two integers denoting the edge of this tree.
输出描述:
Print one integer denoting the answer.
输入
13
10 10 10 10 10 1 10 10 10 1 10 10 10
1 2
2 3
3 4
4 5
2 6
6 7
7 8
7 9
6 10
10 11
11 12
11 13
输出
110

题意:给出一棵树有n个结点,每个点有一个权值,问找三个不相交的子树总权值最大。

树形dp

dp[i][j][0]表示到第i个结点分了j段,折弯下去的状态最大值。

dp[i][j][1]表示到第i个结点分了j段伸上去的状态的最大值。

对于每一个结点0+0,0+1,1+0,1+1,这四种情况0带表子节点折返下去,1代表伸上去

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N=410000;
vector<ll>go[N<<1];
ll n;
ll w[N],dp[N][4][2];
void treedp(ll k1,ll k2)
{
    ll f[4][3];//临时
    ll pre[4][3];
    memset(f,0x00,sizeof f );
    for(int i=0;i<go[k1].size();i++)
    {
        ll j=go[k1][i];
        if(j!=k2)
        {
            treedp(j,k1);
            memcpy(pre,f,sizeof f);
            for(int a=0;a<=3;a++)
            {
                for(int b=0;b<=3;b++)
                {
                    for(int c=0;c<=2;c++)
                    {
                        for(int d=0;d<=1;d++)
                        {
                            if(a+b>3 || c+d>2) continue;
                            f[a+b][c+d]=max(f[a+b][c+d],pre[a][c]+dp[j][b][d]);
                        }
                    }
                }
            }
        }
    }
    for (int i=0;i<4;i++)
    {
        dp[k1][i][0]=max(dp[k1][i][0],f[i][0]);
        dp[k1][i][1]=max(dp[k1][i][1],f[i][1]+w[k1]);
        if (i<3)
        {
            for (int a=0;a<2;a++)
                for (int b=a+1;b<3;b++)
                    dp[k1][i+1][a]=max(dp[k1][i+1][a],f[i][b]+w[k1]);//包含0+0,0+1,1+0,1+1,其中1+1表示连成弯曲的折返子树的情况
        }
    }
}
int main()
{
    memset(dp,0,sizeof(dp));
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
    for(int i=1;i<n;i++)
    {
        ll k1,k2;
        scanf("%lld%lld",&k1,&k2);
        go[k1].push_back(k2);
        go[k2].push_back(k1);
    }
    treedp(1,0);
    ll ans=0;
    for(int i=0;i<=3;i++) ans=max(ans,dp[1][i][0]);
    cout<<ans<<endl;
}
/*

13
10 10 10 10 10 1 10 10 10 1 10 10 10
1 2
2 3
3 4
4 5
2 6
6 7
7 8
7 9
6 10
10 11
11 12
11 13

*/
 

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81162744