zoukankan      html  css  js  c++  java
  • 蒟蒻の树形dp学习总结

    定义

    树形dp,即基于树的结构进行dp

    特质

    一般来说树形dp在设状态转移方程时都可以用f[i][]表示i这颗子树怎么怎么样的最优解,实现时一般都是用子树更新父亲(即从下向上更新),那么首先应该考虑的是一个一个子树的更新父亲还是把所有子树都算完了在更新父亲?这就要因题而异了,一般来说有两种情况:1.需要把所有子树的信息都掌握之后再更新子树的就需要把所有子树都算完了在更新父亲。2.而像树上背包这样的问题就需要一个一个的更新,每次都用一个子树更新已经更新完的子树+父亲,最后就可以将这一部分的子树更新完了,再继续往上更新,最后根节点就是答案。

    其实上面的两种情况可以总结成一种情况就是一个个子树更新父亲,一般来说第一种情况应用更多,也能解决第二情况的问题,只不过如果符合第二种情况的时候用第二种可以速度更快一点,毕竟你省了一遍循环嘛。

    模板

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    vector<int> son[10010];
    int dp[10010][2];//0不参加,1参加
    int v[10010];//记录有没有父节点
    int h[10010];//记录快乐指数
    int n;
    
    void DFS(int x){
        dp[x][0] = 0;
        dp[x][1] = h[x];
        for (int i = 0; i < son[x].size(); i++)
        {
            int y = son[x][i];
            DP(y);
            dp[x][0] += max(dp[y][0],dp[y][1]);
            dp[x][1] += dp[y][0];
        }
    }
    
    int main(){
        cin>>n;
        for (int i = 1; i <=n ; i++)
            scanf("%d",&h[i]);
        for (int i = 1; i <n ; i++)
        {
            int x,y;
            cin>>x>>y;
            v[x] = 1;//x有爸爸
            son[y].push_back(x);//x是y的子节点
        }
        int root;
        for (int i = 1; i <= n; i++)
            if(!v[i]){ //i没有爸爸
                root = i;
                break;
            }
        DFS(root);
        cout << max(dp[root][0],dp[root][1]) << endl;
        return 0;
    }
    

    例题

    P1352 没有上司的舞会

    思路

    老模板了

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 6005
    int h[MAXN];
    int v[MAXN];
    vector<int> son[MAXN];
    int f[MAXN][2];
    void dp(int x)
    {
     f[x][0]=0;
     f[x][1]=h[x];
     for(int i=0;i<son[x].size();i++)
     {
      int y=son[x][i];
      dp(y);
      f[x][0]+=max(f[y][0],f[y][1]);
      f[x][1]+=f[y][0];
     }
    }
    int main()
    {
     int n;
     cin>>n;
     for(int i=1;i<=n;i++) cin>>h[i];
     for(int i=1;i<=n-1;i++)
     {
      int x,y;
      cin>>x>>y;
      son[y].push_back(x);
      v[x]=1;
     }
     int root;
     for(int i=1;i<=n;i++)
     if(!v[i]) {root=i;break;}
     dp(root);
     cout<<max(f[root][0],f[root][1])<<endl;
     return 0;
    }
    
    
    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    「牛客练习赛53A」超越学姐爱字符串
    「CF52C」Circular RMQ
    「Luogu 2367」语文成绩
    「Luogu 1821」[USACO07FEB]银牛派对Silver Cow Party
    「POJ 3268」Silver Cow Party
    「Luogu 1349」广义斐波那契数列
    「CF630C」Lucky Numbers
    「Luogu 3792」由乃与大母神原型和偶像崇拜
    排序机械臂
    P2587 [ZJOI2008]泡泡堂
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/13771247.html
Copyright © 2011-2022 走看看