zoukankan      html  css  js  c++  java
  • 树形dp瞎讲+树形dp基础题题解

    ---恢复内容开始---

    没错

    咕了这么久(没有青青姐久

    我又开始写博客了( ´▽`)

    想了很久些什么(才没有想过呢

    虽然被鄙视基础不好但还是走上了树形dp的不归路

    那么

    就来写写树形dp吧(dtx daolao不要打我

    树形dp是什么呢?

    一言概之,dfs中的动态规划

    emmmmm

    因为没什么固定格式

    就推转移方程(所以我一开始根本找不到讲树形dp的blog

    然后发现了良心博客一枚

    放一下链接

    基本的dp方程

    选择节点类

    dp[i][0]=dp[j][1]
    dp[i][1]=max/min(dp[j][0],dp[j][1]){dp[i][0]=dp[j][1]dp[i][1]=max/min(dp[j][0],dp[j][1])

    树形背包类

    dp[v][k]=dp[u][k]+val
    dp[u][k]=max(dp[u][k],dp[v][k1])

    虽然关于树形dp的博客基本上都是题

    但是看懂了基本dp方程,理解了实质大概就不会特别难(我这句话真严谨

    然后

    题还是有很多的

    就不放题面了

    放链接好了

    要是放一堆图片有假装写了很多的嫌疑

    传送门——>luogu P1352 没有上司的舞会

    核心的代码就是上边放的状态转移方程

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 6010
    
    int fa[maxn],dp[maxn][2];
    int root,n;
    int v[maxn];
    int nxt[maxn],head[maxn];
    
    void treedp(int x){
        for(int i = head[x];i;i = nxt[i]){
            treedp(i);
            dp[x][0] += max(dp[i][1],dp[i][0]);//dp[x][0]代表上司x不来时的最大快乐指数
            dp[x][1] += dp[i][0];//dp[x][1]代表上司来的
        }
    }
    
    int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            scanf("%d",&dp[i][1]);
        for(int i = 1; i < n; i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x] ++;//记录一下有没有上司
            nxt[x] = head[y];
            head[y] = x;//对,像链式前向星的东西(我还理解了好久【划掉
        }
        for(int i = 1; i <= n; i++)
            if(!v[i]) {//没有上司的就是最大上司啦
                root = i;
                break;
            }
        treedp(root);//从树根开始dp
        printf("%d",max(dp[root][0],dp[root][1]));//取最高上司来和不来的最大快乐指数
        return 0;
    }

    emmmmm

    还是蛮好懂的吧

    然后上下一道

    传送门 ———>luogu P1122 最大子树和

    这里有一点点的变化

    就是剪掉了之后是加0

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 16010
    
    int dp[maxn];
    int cnt,head[maxn * 2];
    int f[maxn];//记录当前子节点到之下的花的最大值
    int ans = -2147483647;//因为可能全是负的所以ans搞到最小
    
    struct EDGE{
      int nxt,to;
    }edge[maxn * 2];
    
    void add(int x,int y){
      edge[++cnt].to = y;
      edge[cnt].nxt = head[x];
      head[x] = cnt;
    }//正常的加边看上去真舒服啊
    
    void treedp(int u,int fa){
      f[u] = dp[u];//给f[u]赋值为它本身的大小
      for(int i = head[u];i;i = edge[i].nxt){
        int v = edge[i].to;//v是u的儿子
        if(v != fa){//唔防止双向加边跑回去
          treedp(v,u);
          f[u] += max(0,f[v]);
        }
      }
      ans = max(ans,f[u]);//反正所有的花都在一根上不需要加和什么的(我在说什么废话
    }
    
    int main(){
      int n;
      scanf("%d",&n);
      for(int i = 1;i <= n;i++)
        scanf("%d",&dp[i]);
      for(int i = 1;i < n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
      }
      treedp(1,0);//将1的父节点定义为0
      printf("%d",ans);
      return 0;
    }

    唔嗷【好困

    (明天的联欢是我写博客的动力【不小心暴露了什么

    下一道来

    传送门———>luogu P2016 战略游戏

    (吓死我了插链接的时候突然闪退了(╥﹏╥)还好有自动保存这种可爱的东西

    emmmm

    这道题似乎又回到了原点?

    其实跟没有上司的舞会很像

    就是上司不来,下属必须来

    上司来,下属来不来都行

    (有点像开会?总得来一个负责人,当然都希望来的越少越好了【因为懒

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 1510
    
    struct EDGE{
      int nxt,to;
    }edge[maxn];
    
    int cnt,head[maxn];
    int v[maxn];
    int dp[maxn][2];
    
    void add(int x,int y){
      edge[++cnt].to = y;
      edge[cnt].nxt = head[x];
      head[x] = cnt;
    }
    
    void treedp(int x){
      dp[x][1] = 1;//放的地方都是一
      for(int i = head[x];i;i = edge[i].nxt){
        int u = edge[i].to;
        treedp(u);
        dp[x][0] += dp[u][1];//当前点不放,下一个点一定要放
        dp[x][1] += min(dp[u][1],dp[u][0]);当前放了下一个点不一定放不放
      }
    }
    
    int main(){
      int n;
      scanf("%d",&n);
      for(int i = 0;i < n;i++){
        int r,k;
        scanf("%d%d",&r,&k);
        for(int j = 0;j < k;j++){
          int p;
          scanf("%d",&p);
          v[p]++;
          add(r,p);
        }
      }
      int root;
      for(int i = 0;i < n;i++)
        if(!v[i]){
          root = i;
          break;
        }//唔又是找根
      treedp(root);
      printf("%d",min(dp[root][0],dp[root][1]));
      return 0;
    }

    啊友情提示

    a掉这道题之后可以顺道a掉luogu UVA1292 Strategic game

    差别就是这道题要输入多组数据而已

    /*

    emmmmm

    去写选课

    写完就发

     */

    好的我鸽了

    告辞【快速溜

  • 相关阅读:
    jquery学习
    java--MVC引入JUnit单元测试
    BAE引擎发布到外网
    ORACLE1.26 综合:游标和动态SQL
    ORACLE1.25 动态SQL
    ORACLE1.24 银行系统操作和游标
    ORACLE1.23 loop,whild.for循环
    ORACLE1.23 if case when
    ORACLE1.22 %type %rowtype
    ORACLE1.21 PLSQL 01
  • 原文地址:https://www.cnblogs.com/sevenyuanluo/p/10192869.html
Copyright © 2011-2022 走看看