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;
    }
  • 相关阅读:
    Redis在win7上的可视化应用
    MemCache在win7上的可视化配置以及Nodejs/Net应用
    如何让nodejs同步操作
    Asp.Net Web API 2第十四课——Content Negotiation(内容协商)
    Redis for Windows(C#缓存)配置文件详解
    Redis for Windows(C#缓存)安装和使用
    Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化
    Asp.Net Web API 2第十二课——Media Formatters媒体格式化器
    Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver
    Asp.Net Web API 2第十课——使用OWIN自承载Web API
  • 原文地址:https://www.cnblogs.com/shimu/p/5776372.html
Copyright © 2011-2022 走看看