zoukankan      html  css  js  c++  java
  • 牛客多校Round 2

    Solved:3

    rank:187

    H.travel

    题意:给一颗带有点权的树 找三条不相交的链 使得点权最大

    题解:使用树形DP dp[x][i][0/1] 表示x节点选择i条链 有没有经过x的链

       对于每一个回溯的状态 下面的结点已经处理好了

       但是处理当前结点时还有一种有两条经过x的链 实际上他们可以合成一条链

       为了避免重复计算 经过当前结点的权值在更新时计算

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int n;
    ll val[400005];
    ll dp[400005][4][2];
    vector<int> g[400005];
    
    void dfs(int x, int fa)
    {
        ll tmp[4][3]; ll f[4][3];
        for(int i = 0; i < 4; i++) tmp[i][0] = tmp[i][1] = tmp[i][2] = 0;
        for(int i = 0; i < g[x].size(); i++)
        {
            int v = g[x][i];
            if(v == fa) continue;
            dfs(v, x);
            memcpy(f, tmp, sizeof(tmp));
    
            for(int a = 0; a < 4; a++)
                for(int b = 0; b < 4; b++)
                {
                    if(a + b > 3) continue;
                    for(int c = 0; c < 3; c++)
                        for(int d = 0; d < 2; d++)
                        {
                            if(c + d > 2) continue;
                            tmp[a + b][c + d] = max(tmp[a + b][c + d], f[a][c] + dp[v][b][d]);
                        }
                }
        }
        for(int i = 0; i < 4; i++)
        {
            dp[x][i][0] = max(dp[x][i][0], tmp[i][0]);
            dp[x][i][1] = max(dp[x][i][1], tmp[i][1] + val[x]);
    
            if(i < 3)
            {
                for(int j = 0; j < 2; j++)
                    for(int k = j + 1; k < 3; k++)
                        dp[x][i + 1][j] = max(dp[x][i + 1][j], tmp[i][k] + val[x]);
            }
        }
    }
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%lld", &val[i]);
        for(int i = 1; i < n; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1, -1);
        ll ans = 0;
        for(int i = 0; i < 4; i++) ans = max(ans, dp[1][i][0]);
        printf("%lld
    ", ans);
        return 0;
    }
    /*
    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
    */
    View Code

       

  • 相关阅读:
    CloudFlare Workers 反代任意网站和挂载单页代码
    排查Linux服务器是否有被入侵方法总结
    修复Windows time时间服务无法自动启动的问题
    如何删除windows服务
    linux之NetHogs与nload流量监控
    常用IPV4 DNS服务器与常用IPV6 DNS服务器
    Win10系统如何删除网络及修改网络名称
    window修改远程桌面RDP方法
    单击鼠标右键菜单显示怎么在左边?
    传统IDC机房部署网站
  • 原文地址:https://www.cnblogs.com/lwqq3/p/9349715.html
Copyright © 2011-2022 走看看