zoukankan      html  css  js  c++  java
  • 树形dp入门

     

    hdu1520

    题意:有n个人参加派对,每个人有一个“开心值”,如果某个人的直接主管参加派对,那么他将不会参加派对,问派对上所有人的“开心值”的最大总和。(注意这道题是多组输入,不然会直接wa。。QAQ)

    解题思路:我们可以以按主管关系建树,dp【i】【0】为当i不去时,他的子树最大的“开心值”,设u为父节点,v为子节点,那么有dp【u】【0】+=max(dp【v】【0】,dp【v】【1】),dp【u】【1】+=dp【v】【0】;

    我们假设1为该树的根节点,那么答案就为max(dp【1】【0】,dp【1】【1】)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<vector>
     6 #include<stack>
     7 #include<cstdio>
     8 #include<map>
     9 #include<set>
    10 #include<string>
    11 #include<queue>
    12 using namespace std;
    13 #define inf 0x3f3f3f3f
    14 typedef long long ll;
    15 inline ll gcd(ll i,ll j){
    16     return j==0?i:gcd(j,i%j);
    17 }
    18 inline ll lcm(ll i,ll j){
    19     return i/gcd(i,j)*j;
    20 }
    21 const int maxn=6e3+5;
    22 int dis[maxn];
    23 vector<int > vec[maxn];
    24 int n;
    25 int dp[maxn][2];
    26 void dfs(int u,int fa)
    27 {
    28     dp[u][1]=dis[u];
    29     int l=vec[u].size();
    30     for(int i=0;i<l;i++){
    31         int v=vec[u][i];
    32         if(v!=fa){
    33             dfs(v,u);
    34             dp[u][0]+=max(dp[v][0],dp[v][1]);
    35             dp[u][1]+=dp[v][0];
    36         }
    37     }
    38 }
    39 int main(){
    40     while(~scanf("%d",&n)){
    41         for(int i=1;i<=n;i++){
    42         scanf("%d",&dis[i]);
    43         dp[i][0]=dp[i][1]=0;
    44         vec[i].clear();
    45     }
    46     int u,v;
    47     while(scanf("%d%d",&u,&v)){
    48         if(u==0&&v==0){
    49             break;
    50         }
    51         vec[u].push_back(v);
    52         vec[v].push_back(u);
    53     }
    54     dfs(1,-1);
    58     cout<<max(dp[1][0],dp[1][1])<<endl;
    59     }
    60     return 0;
    61 }

     hdu2196

    题意:分别求每个叶子结点到某个结点的最大距离(推荐)

    解题思路:由于使用dfs获得信息,只能先得到子节点的信息,然后才能得到父节点的信息,也就是说当更新某子节点时,无法得到该节点父节点方向的信息,所以一次dfs是没有办法得到答案的。我们可以定义状态dp【i】【0】为以i为根节点,往某子结点方向所能前进的最长距离,dp【i】【1】为次远距离(注意dp【i】【0】,和dp【i】【1】所往的子结点方向不同),dp【i】【2】为以i为源点往i的父节点方向的最大长度。设u为父节点,v为子节点,w为两结点的距离。第一次dfs从下往上

    ,那么有dp【u】【0】=max(dp【u】【0】,dp【v】【0】+w)。第二次dfs,从上往下,当dp【u】【0】!=dp【v】【0】+w时,有dp【v】【2】=max(dp【u】【0】,dp【u】【2】)+w,否者dp【v】【2】=max(dp【u】【1】,dp【u】【2】)+w。(对状态转移方程有疑问的可以画图理解)

    最后依次输出max(dp【i】【0】,dp【i】【2】);

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<stack>
    #include<cstdio>
    #include<map>
    #include<set>
    #include<string>
    #include<queue>
    using namespace std;
    #define inf 0x3f3f3f3f
    typedef long long ll;
    inline ll gcd(ll i,ll j){
        return j==0?i:gcd(j,i%j);
    }
    inline ll lcm(ll i,ll j){
        return i/gcd(i,j)*j;
    }
    struct st{
        int to;
        int wi;
        st():to(0),wi(0){}
        st(int to,int wi):to(to),wi(wi){}
    };
    const int maxn=1e4+5;
    vector<st > vec[maxn];
    int dp[maxn][3];
    void dfs1(int u,int fa){
        dp[u][0]=0;
        dp[u][1]=0;
        for(int i=0;i<vec[u].size();i++){
            int v=vec[u][i].to;
            int wi=vec[u][i].wi;
            if(v!=fa){
                dfs1(v,u);
                int tem=dp[v][0]+wi;
                if(tem>dp[u][0]){
                    dp[u][1]=dp[u][0];
                    dp[u][0]=tem;
                }
                else if(tem>dp[u][1]){
                    dp[u][1]=tem;
                }
            }
        }
    }
    void dfs2(int u,int fa){
        for(int i=0;i<vec[u].size();i++){
            int v=vec[u][i].to;
            int w=vec[u][i].wi;
            if(v!=fa){
                if(dp[u][0]!=dp[v][0]+w){
                    dp[v][2]=max(dp[u][0],dp[u][2])+w;
                }
                else{
                    dp[v][2]=max(dp[u][1],dp[u][2])+w;
                }
                dfs2(v,u);
            }
        }
    }
    int main(){
        int n;
        int wi,v;
        while(~scanf("%d",&n)){
                memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                vec[i].clear();
            }
            for(int i=2;i<=n;i++){
                scanf("%d%d",&v,&wi);
                vec[i].push_back(st(v,wi));
                vec[v].push_back(st(i,wi));
            }
            dfs1(1,-1);
            dfs2(1,-1);
            for(int i=1;i<=n;i++)
            printf("%d
    ",max(dp[i][0],dp[i][2]));
            /*for(int i=1;i<=n;i++){
                cout<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<endl;
            }*/
        }
        return 0;
    }

     

  • 相关阅读:
    SDUT 2143 图结构练习——最短路径 SPFA模板,方便以后用。。 Anti
    SDUT ACM 1002 Biorhythms 中国剩余定理 Anti
    nyist OJ 119 士兵杀敌(三) RMQ问题 Anti
    SDUT ACM 2157 Greatest Number Anti
    SDUT ACM 2622 最短路径 二维SPFA启蒙题。。 Anti
    二叉索引树 区间信息的维护与查询 Anti
    SDUT ACM 2600 子节点计数 Anti
    UVA 1428 Ping pong 二叉索引树标准用法 Anti
    2010圣诞Google首页效果
    Object
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/10323171.html
Copyright © 2011-2022 走看看