• 树形DP


    1.没有上司的舞会

    某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

    用f[i][0]表示不选择i点时,i点及其子树能选出的最多人数,f[i][1]表示选择i点时,i点及其子树的最多人数。

    第二步:确定状态转移方程

    f[i][0] = Σ(max (f[j][0], f[j][1]))

    f[i][1] = 1+ Σf[j][0]

    (j是i的儿子!!)

    边界:f[i][0] = 0, f[i][1] = 1  --------i是叶子节点 

    结果为max(f[root][0], f[root][1])

    void dfs(long x)
    {
        v[x] = 1;
        for (long i=1; i<=n; i++)
        {
            if ((!v[i]) && (fa[i] == x))
            {
                dfs(i);
                f[x][0] += max(f[i][1], f[i][0]);
                f[x][1] += f[i][0];
            }
        }
    }

    2.二叉苹果树

    有一棵苹果树,苹果树的是一棵二叉树,共N个节点,树节点编号为1~N,编号为1的节点为树根,边可理解为树的分枝,每个分支都长着若干个苹果,现在要要求减去若干个分支,保留M个分支,要求这M个分支的苹果数量最多。

    第一步:确定状态

    f[u][j]表示在以u为根的子树保留j个分支可以得到的最大苹果数量

    第二步:确定状态转移方程

    F[u][j] = max(f[u][k] + f[v][j – k - 1] + W)

    v分别是u的儿子,w为u到v边上的苹果数目, k属于[0, j]

    void dfs(int u)
    {
         vis[u]=1;
          int i,v,w,j,k,son=0;
          for(i=head[u];i!=-1;i=e[i].next)
          {
    	 v=e[i].ed;w=e[i].w;
    	 if(vis[v]==1)continue;
    	 dfs(v);
    	 for(k=m;k>=1;k--)
    	 {
    	       for(j=1;j<=k;j++)//在v节点的子树中选择j条边
                             if(f[u][k]<f[u][k-j]+f[v][j-1]+w)
    		    f[u][k]=f[u][k-j]+f[v][j-1]+w;
                                  //u与v有一条边,所以加上dp[v][j-1]
               }
         }
    }		
    

    3.Strategic game

    一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。

    第一步:确定状态

    f[x][1]以x为根的子树在x上放置的士兵的最少所需的士兵数目

    f[x][0]以x为根的子树x上不放置的士兵的最少所需的士兵数目

    第二步:确定状态转移方程

    f[x][1] =1 + Σ min(f[i][0],f[i][1]) 

    // x上放置的士兵,于是它的儿子们可放可不放!

    f[x][0] = Σ f[i][1]           

    //x上不放置的士兵,它的儿子们都必须放!

    (i是x的儿子!!)

    结果为min(f[root][0], f[root][1])

    void dfs(long x)
    
    {
    
        v[x] = 1;
    
        for (long i=0; i<n; i++)
    
        {
    
           if ((!v[i]) && (b[x][i]))
    
            {
    
                dfs(i);
    
                f[x][0] += f[i][1];
    
                f[x][1] += min(f[i][0], f[i][1]);
    
            }
    
        }
    
    }
    

    4.Cell Phone Network

    给你一棵无向树,问你最少用多少个点可以覆盖掉所有其他的点。(一个点被盖,它自己和与它相邻的点都算被覆盖)

    int dp[MAXN][MAXN];   //dp[i][0]表示取i结点时的最小结点数
                          //dp[i][1]表示不取i结点时,i被其儿子覆盖时的最小结点数
                          //dp[i][2]表示不选点i,i被其父亲覆盖时的最小结点数
                          //树形DP状态转移从叶子结点开始向根不断转移,所以用深搜。
                          //搜到叶子结点就结束。
                          //转移的时候可以将结点以下给圈起来。
                          //取与不取,树上背包
    int vis[MAXN];
    void dfs(int u)
    {
        vis[u]=1;
        int i;
        int flag=1,tmp=INF;
        for(i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(!vis[v])                             //额,图的最小支配集吧
            {
                dfs(v);
                dp[u][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
                dp[u][2]+=min(dp[v][0],dp[v][1]);   //不取的话,肯定没有父亲这个选项啊
                                                    //父亲只有一个,所以不必做过多的讨论
                                                    //儿子比较多,可以取所有儿子,但必须选一个儿子
                                                    //但选了一个儿子就要做标记
                if(dp[v][0]<=dp[v][1])
               {
                  dp[u][1]+=dp[v][0];
                  flag=0;
               }
                else
               {
                  dp[u][1]+=dp[v][1];
                  tmp=min(tmp,dp[v][0]-dp[v][1]);
               }
            }
        }
        if(flag)    //还没有选儿子,加上这个差值,补回一个儿子
        dp[u][1]+=tmp;
        return ;
    }

  • 相关阅读:
    谈屡面屡胜的面试经验
    同步异步和阻塞非阻塞的区别
    Ansible条件测试
    Ansible playbook基础组件介绍
    Ansible的基础元素和YAML介绍
    Ansible常见模块介绍
    Ansible介绍及安装部署
    Spark介绍及安装部署
    安装部署Apache Hadoop (完全分布式模式并且实现NameNode HA和ResourceManager HA)
    安装部署Apache Hadoop (本地模式和伪分布式)
  • 原文地址:https://www.cnblogs.com/Accpted/p/11215789.html
Copyright © 2020-2023  润新知