• 树形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;
    }

     

  • 相关阅读:
    Vocabulary Recitation 2020/05/06
    java set TreeSet详解
    vue快速入门~必备基础知识(一)下~过滤器
    vue快速入门~必备基础知识(一)上
    vue入门(二)基于前面的基础的一个小Demo
    Annotation注释详解~
    泛型~详解~
    Collections工具类详解
    TreeMap实现类和SortMap接口
    Map集合-主要HashMap和Hashtable
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/10323171.html
Copyright © 2020-2023  润新知