• hdu2196 树形dp


    想法:对于一棵树,对于任意一个节点,它的最大值可以来自以它为根的子树,也可以来自它的父亲。
    所以需要考虑二个方向的情况。所以必须考虑2个方向。
    解法:dp[i][0]保存子树的值,dp[i][1]保存父亲结点方向+dis[i,root];
    可以先一遍dfs,保存任意点子树的最大值,同时保存任意点取最大值的方向,同时维护他的第二大值。
    然后进行第二次dfs,对于结点u,如果它的孩子不是它取最大值路径上的点,那么孩子的值dp[i][1]为
    max(dp[root][1], dp[root][0])+ dis[i,root];不然dp[i][1]为父亲结点的第二大值 + dis[i,root];
    然后第二大值为dp[i][1];

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int MAXN = 10010;
    struct node
    {
        int to;
        int v;
        int next;
    }edge[MAXN*3];
    int pre[MAXN],index,vis[MAXN],n;
    int dp[MAXN][2],way[MAXN],sv[MAXN];
    //sv[]存第另一边的 不是子树的 way[]表示当前点最大值从哪里来
    //dp[][0]表示子树方向的最大值 dp[][1]表示另一方向的最大值
    int max(int x,int y){
        return x>y?x:y;
    }
    int min(int x,int y){
        return x<y?x:y;
    }
    void add(int x,int y,int z)
    {
        edge[index].to = y;
        edge[index].v = z;
        edge[index].next = pre[x];
        pre[x] = index++;
    }
    void dfs1(int root)
    {
        vis[root] = 1;
        int i;
        int set = root;
        for(i=pre[root]; i!=-1; i=edge[i].next){
            int t = edge[i].to;
            if(!vis[t]){
                dfs1(t);
                if(dp[root][0] > dp[t][0] + edge[i].v){
                    sv[root] = max(sv[root], dp[t][0] + edge[i].v);
                }
                else {
                    set = t;
                    sv[root] = dp[root][0];
                    dp[root][0] = dp[t][0] + edge[i].v;
                }
            }
        }
        way[root] = set;
    }
    void dfs2(int root)
    {
        vis[root] = 1;
        int i;
        for(i=pre[root]; i!=-1; i=edge[i].next){
            int t = edge[i].to;
            if(!vis[t]){
                if(way[root] != t){
                    dp[t][1] = max(dp[root][0], dp[root][1]) + edge[i].v;
                    sv[t] = dp[t][1];
                }
                else {
                    dp[t][1] = sv[root] + edge[i].v;
                    sv[t] = dp[t][1];
                }
                dfs2(t);
            }
        }
    }
    int main()
    {
        int i;
        while(~scanf("%d",&n))
        {
            index = 1;
            memset(sv,0,sizeof(sv));
            memset(dp,0,sizeof(dp));
            memset(pre,-1,sizeof(pre));
            for(i=2; i<=n; ++i){
                int x,v;
                scanf("%d %d",&x, &v);
                add(i, x, v);
                add(x, i, v);
            }
            memset(vis,0,sizeof(vis));
            dfs1(1);
            /*for(i=1; i<=n; i++){
                printf("%d  ",sv[i]);
            }
            cout<<endl;*/
            memset(vis,0,sizeof(vis));
            dfs2(1);
            for(i=1; i<=n; i++){
                printf("%d
    ",max(dp[i][0],dp[i][1]));
            }
        }
    }
    /*
    7
    1 1
    1 1
    2 1
    2 1
    3 1
    3 1
    8
    1 1
    1 1
    2 1
    2 1
    3 1
    5 1
    7 1
    */
  • 相关阅读:
    HDU1294 Rooted Trees Problem(整数划分 组合数学 DP)
    HDU2546 饭卡(背包)
    经典动态规划总结
    POJ1285 Combinations, Once Again(背包 排列组合)
    计数 组合数学总结
    莫队算法 2038: [2009国家集训队]小Z的袜子(hose)
    循环-24. 求给定序列前N项和之二
    循环-23. 找完数
    循环-22. 输出闰年
    循环-21. 求交错序列前N项和
  • 原文地址:https://www.cnblogs.com/sweat123/p/5020312.html
Copyright © 2020-2023  润新知