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;
}
原文地址:https://www.cnblogs.com/shimu/p/5776372.html