• HDU_2196 树形DP


    题目的大意是:有一棵N个节点的树(N<10000),树的每一条边都有一个边权,求这棵树上每个节点的最长链长。

    用树形dp来写,dp[i]代表第i个节点的最长链的长度,dp1[i]代表第i个节点在其和其子树上的最长链的长度,dp3[[i]代表第i个节点向上的最长链的长度,这样我们写出转移方程:

    dp[i] = max(dp1[i],dp3[i])。 

    dp1[i]我们只需要一次最简单的dfs从根(1)遍历到叶子节点就好了,dp3[i]要怎么求?dp3[i]代表第i个节点往上的最长链,我们在往上找i的根节点fa[i],不妨叫做fa。那么dp3[i]的的值就是dp3[fa]和fa节点往下(除了i节点以外的子树的最长链),这个时候我们就需要一个dp2[i]代表第i个节点及其子树的第二长链。这样我们得到dp3[i]的转移方程;

    dp3[i] = max{dp3[fa],g[fa][i]+dp1[i] == dp1[fa] ? dp2[fa]:dp1[fa]}+g[fa][i]。其中g[fa][i]代表的是边的权值:

    这样我们在用一个dfs来遍历得到所有的dp3[i],dp2[i]可以再得到dp1[i]是得到,下面是ac代码:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #define ll long long
    #define FOR(i,x,y) for(int i = x;i < y;i ++)
    #define INF 1<<31
    
    using namespace std;
    
    const int MAXN = 11111;
    
    int dp1[MAXN],dp2[MAXN],dp3[MAXN],dp[MAXN];
    int N;
    vector <pair<int,int> > G[MAXN];
    
    
    //得到dp1[i],dp2[i]
    int dfs1(int u,int fa){
        dp1[u] = 0; dp2[u] = 0;
        int tem[MAXN],tem_cnt = 0;
        vector <pair<int,int> > :: iterator it;
        for(it = G[u].begin();it != G[u].end();it ++){
            int v = it->first,val = it->second;
            if(v == fa) continue;
            tem[tem_cnt++] = val+dfs1(v,u);
        }
        sort(tem,tem+tem_cnt);
        if(tem_cnt >= 2){
            dp1[u] = tem[tem_cnt-1];    dp2[u] = tem[tem_cnt-2];
        }
        else if(tem_cnt == 1)   dp1[u] =tem[tem_cnt-1];
        return dp1[u];
    }
    
    
    //求出所有dp3[i],其实这里就可以求出dp[i]了
    void dfs3(int u,int fa){
        vector <pair<int,int> > :: iterator it;
        for(it = G[u].begin();it != G[u].end();it ++){
            int v = it->first,val = it->second;
            if(v == fa) continue;
            if(dp1[u] == dp1[v]+val)    dp3[v] = max(dp2[u],dp3[u]) + val;
            else    dp3[v] = max(dp1[u],dp3[u]) + val;
            dfs3(v,u);
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d",&N)){
            FOR(i,1,N+1) G[i].clear();
            int to,val; //val代表的是编的权值
            FOR(i,2,N+1){
                scanf("%d%d",&to,&val);
                G[i].push_back(make_pair(to,val));
                G[to].push_back(make_pair(i,val));
            }
            dfs1(1,-1);
            dp3[1] = 0;
            dfs3(1,-1);
            FOR(i,1,N+1)    dp[i] = max(dp1[i],dp3[i]);
            FOR(i,1,N+1)    printf("%d
    ",dp[i]);
        }
        return 0;
    }
    


  • 相关阅读:
    asp.net 页面元素分析搜集
    ASP.NET AJAX深入浅出系列UpdatePanel的使用笔记(上)
    用sql语句来管理数据库日志问题
    C# .NET学习网站(转)
    Visual Studio .Net团队开发[转]
    sql 语句大全
    Word中快速操作的10个技巧
    嫁给程序员的好处
    关于手机病毒时代到来的担忧
    自己工作用过的SQL代码(1)
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4555877.html
Copyright © 2020-2023  润新知