zoukankan      html  css  js  c++  java
  • hdu5834 树型dp

    赛场上队友都想出来了,居然弱得没调出来,,,
    树型dp,dp1[u],dp2[u]分别代表从u开始(包括u)往子节点走回到u和不回到u所能取得的最大值
    dp3[u],dp4[u]分别代表不包括自身向父节点走回来和不回来的最大值
    两个dfs走一下就好,注意有很多细节
    代码里面注释一下好了,,,毕竟调了那么久
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <stack>
    //#pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std;
    #define PF(x) cout << "debug: " << x << " ";
    #define EL cout << endl;
    #define PC(x) puts(x);
    typedef long long ll;
    #define CLR(x, v) sizeof (x, v, sizeof(x))
    using namespace std;
    const int INF = 0x5f5f5f5f;
    const int N = 1000050;
    struct Edge
    {
        int to, cost;
        Edge(int to, int c) : to(to), cost(c) {}
        Edge() {}
    };
    vector<Edge> G[N];
    
    int dp1[N], dp2[N], //dp2回来 dp1不回来
    dp3[N], dp4[N],ans[N][5],a[N]; // dp4回来 dp3不回来
    
    void dfs(int u, int fa)
    {
    
        int cnt=G[u].size();
        for (int  i = 0; i < cnt; ++i)
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
            dfs(v, u);
    
            if (dp2[v]-c*2 > 0) dp2[u] += dp2[v]-c*2;//从这个子节点回来不亏就加上
        }
        for(int i=0; i<cnt; i++)//遍历到底停在那个子树上最大值
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
            if(dp2[v]-2*c > 0)
            {
                if( dp1[u]<dp2[u]+c-(dp2[v]-dp1[v]))
                {
                    dp1[u]=dp2[u]+c-(dp2[v]-dp1[v]);
    
                    ans[u][0]=v;//记录最大值
    
                }
            }
            else if(dp1[v]>c)
            {
                if(dp1[u]<dp2[u]+dp1[v]-c)
                {
                    dp1[u]=dp2[u]+dp1[v]-c;
    
                    ans[u][0]=v;
    
                }
            }
    
    
        }
        int max1=a[u];
        for(int i=0; i<cnt; i++)//遍历寻找次大值
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
            if(dp2[v]-2*c > 0)
            {
                if( max1<dp2[u]+c-(dp2[v]-dp1[v])&&v!=ans[u][0])
                {
                    max1=dp2[u]+c-(dp2[v]-dp1[v]);
     
                    ans[u][1]=i;//此处记录的是不定长数组中的序号
     
                }
            }
            else if(dp1[v]>c)
            {
                if(max1<dp2[u]+dp1[v]-c&&v!=ans[u][0])
                {
                    max1=dp2[u]+dp1[v]-c;
     
                    ans[u][1]=i;
     
                }
            }
     
     
        }
     
    }
    void dfs1(int u, int fa)
    {
        int cnt=G[u].size();
     
        for (int i = 0; i < cnt; ++i)
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
     
            int num;
     
            if(dp2[v] > 2 * c)//求dp4[v]时只需要判断这个即可
            {
                num=dp2[u]-dp2[v]+2*c;
                dp4[v]=max(dp4[v],dp4[u]+num-2*c);
            }
            else
            {
                dp4[v]=max(dp4[v],dp4[u]+dp2[u]-2*c);
            }
     
     
            if(v != ans[u][0])//当v并非dp1[u]停留的最大子树
            {
     
                if(dp2[v] > 2*c)
                {
                    dp3[v] = max(dp3[v], dp1[u] - (dp2[v] - 2*c) + dp4[u]-c);//v向父亲和兄弟中探索依然停留在ans[u][0]
                    dp3[v] =max(dp3[v],dp2[u]-(dp2[v]-2*c)+dp3[u]-c);//停留在父亲及以上节点中,用上下两个max对两种情况比较
                }
                else
                {
                    dp3[v] = max(dp3[v], dp1[u]+dp4[u]-c);
                    dp3[v] =max(dp3[v],dp2[u]+dp3[u]-c);
                }
     
            }
     
            else
            {
     
                if(ans[u][1]==-1)//当不存在次大点
                {
                    int max1=dp1[u]-(dp1[v]-c);
                    dp3[v]=max(dp3[v],dp3[u]-c+max1);
     
                }
     
                else
                {
                    int v1=G[u][ans[u][1]].to;
     
                    int c1=G[u][ans[u][1]].cost;
     
                    int max1=dp1[u]-(dp1[v]-c),max2;//max1代表当没有最大点那棵子树的值,max2代表在max1情况下停留在次大点的值
     
                    if(dp2[v1]>2*c1)
                        max2=max1-(dp2[v1]-2*c1)+(dp1[v1]-c1);
                    else
                        max2=max1+dp1[v1]-c1;
     
                    dp3[v]=max(dp3[v],max2+dp4[u]-c);//最终停留在次大点
     
                    dp3[v]=max(dp3[v],max1+dp3[u]-c);//最终停留在父节点或以上
     
                }
     
     
            }
            dfs1(v,u);
        }
     
     
    }
    int main()
    {
        int T;
        int cas=0;
       // freopen("in.txt","r",stdin);
     
     
        cin>>T;
        while (T--)
        {
     
            cas++;
            int n;
            scanf("%d", &n);
            for (int i = 1; i <= n; ++i)
            {
                scanf("%d", a+i);
                ans[i][0]=-1;
                ans[i][1]=-1;
            }
            int u, v, c;
            for (int i = 1; i <=n; ++i)
            {
                G[i].clear();
                dp1[i] = dp2[i] = a[i];
                dp3[i] = dp4[i] = 0;
            }
            for (int i = 1; i < n; ++i)
            {
                scanf("%d%d%d", &u, &v, &c);
                G[u].push_back(Edge(v, c));
                G[v].push_back(Edge(u, c));
            }
            dfs(1, -1);
     
            dfs1(1,-1);
            printf("Case #%d:
    ",cas);
            for(int i=1; i<=n; i++)
            {
     
                cout<<max(dp1[i]+dp4[i],dp2[i]+dp3[i])<<endl;
            }
     
        }
        return 0;
    }
     

     下面是精简版,参考自

    http://blog.csdn.net/fsss_7/article/details/52210266

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <stack>
    //#pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std;
    #define PF(x) cout << "debug: " << x << " ";
    #define EL cout << endl;
    #define PC(x) puts(x);
    typedef long long ll;
    #define CLR(x, v) sizeof (x, v, sizeof(x))
    using namespace std;
    const int INF = 0x5f5f5f5f;
    const int N = 1000050;
    struct Edge
    {
        int to, cost;
        Edge(int to, int c) : to(to), cost(c) {}
        Edge() {}
    };
    vector<Edge> G[N];
    int dp1[N], dp2[N], //dp2回来 dp1不回来
    dp3[N], dp4[N],ans[N][5],a[N]; // dp4回来 dp3不回来
    void dfs(int u, int fa)
    {
        int cnt=G[u].size();
        for (int  i = 0; i < cnt; ++i)
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
            dfs(v, u);
            dp1[u]=max(dp1[u],dp1[u]+dp2[v]-2*c);
            if(dp2[u]+dp1[v]-c>dp1[u]) ans[u][0]=v;
            dp1[u]=max(dp1[u],dp2[u]+dp1[v]-c);
            dp2[u]=max(dp2[u],dp2[u]+dp2[v]-2*c);
    
        }
    }
    void dfs1(int u, int fa)
    {
        int cnt=G[u].size();
    
        for (int i = 0; i < cnt; ++i)
        {
            int v = G[u][i].to;
            int c = G[u][i].cost;
            if (v == fa) continue;
    
            int num;
            if(dp2[v] > 2 * c)//求dp4[v]时只需要判断这个即可
            {
                num=dp2[u]-dp2[v]+2*c;
                dp4[v]=max(dp4[v],dp4[u]+num-2*c);
            }
            else
            {
                dp4[v]=max(dp4[v],dp4[u]+dp2[u]-2*c);
            }
            if(v != ans[u][0])//当v并非dp1[u]停留的最大子树
            {
                if(dp2[v] > 2*c)
                {
                    dp3[v] = max(dp3[v], dp1[u] - (dp2[v] - 2*c) + dp4[u]-c);//v向父亲和兄弟中探索依然停留在ans[u][0]
                    dp3[v] =max(dp3[v],dp2[u]-(dp2[v]-2*c)+dp3[u]-c);//停留在父亲及以上节点中,用上下两个max对两种情况比较
                }
                else
                {
                    dp3[v] = max(dp3[v], dp1[u]+dp4[u]-c);
                    dp3[v] =max(dp3[v],dp2[u]+dp3[u]-c);
                }
    
            }
            else
            {
                int max1=0,num;
                num=dp1[v]-c;
                num=dp1[u]-num;
                for(int j=0;j<cnt;j++){
                    int v1 = G[u][j].to;
                    int c1 = G[u][j].cost;
                    if (v1 == fa) continue;
                    if(v1==v) continue;
                    if(dp2[v1]>2*c1){
                        max1=max(max1,num-(dp2[v1]-2*c1)+dp1[v1]-c1+dp4[u]-c);
                    }
                    else
                        max1=max(max1,num+dp1[v1]-c1+dp4[u]-c);
                    }
              max1=max(max1,num+dp3[u]-c);
              dp3[v]=max(dp3[v],max1);
            }
            dfs1(v,u);
        }
    
    
    }
    int main()
    {
        int T;
        int cas=0;
      //  freopen("in.txt","r",stdin);
        cin>>T;
        while (T--)
        {
            cas++;
            int n;
            scanf("%d", &n);
            for (int i = 1; i <= n; ++i)
            {
                scanf("%d", a+i);
                ans[i][0]=-1;
                ans[i][1]=-1;
            }
            int u, v, c;
            for (int i = 1; i <=n; ++i)
            {
                G[i].clear();
                dp1[i] = dp2[i] = a[i];
                dp3[i] = dp4[i] = 0;
            }
            for (int i = 1; i < n; ++i)
            {
                scanf("%d%d%d", &u, &v, &c);
                G[u].push_back(Edge(v, c));
                G[v].push_back(Edge(u, c));
            }
            dfs(1, -1);
            dfs1(1,-1);
            printf("Case #%d:
    ",cas);
            for(int i=1; i<=n; i++)
            {
    
                cout<<max(dp1[i]+dp4[i],dp2[i]+dp3[i])<<endl;
            }
    
        }
        return 0;
    }
  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/shimu/p/5776372.html
Copyright © 2011-2022 走看看