zoukankan      html  css  js  c++  java
  • HDU 1561 The more, The Better 经典树形DP

    The more, The Better

    Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4442    Accepted Submission(s): 2639


    Problem Description
    ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?
     
    Input
    每个测试实例首先包括2个整数,N,M.(1 <= M <= N <= 200);在接下来的N行里,每行包括2个整数,a,b. 在第 i 行,a 代表要攻克第 i 个城堡必须先攻克第 a 个城堡,如果 a = 0 则代表可以直接攻克第 i 个城堡。b 代表第 i 个城堡的宝物数量, b >= 0。当N = 0, M = 0输入结束。
     
    Output
    对于每个测试实例,输出一个整数,代表ACboy攻克M个城堡所获得的最多宝物的数量。
     
    Sample Input
    3 2
    0 1
    0 2
    0 3
    7 4
    2 2
    0 1
    0 4
    2 1
    7 1
    7 6
    2 2
    0 0
     
    Sample Output
    5
    13
     
    这是一道经典的树形DP,去年去凤凰之前就碰到过这道题目了。但是没有看懂思路。
    额额,居然拖到现在.
     
    思路:
         一看就感觉是背包,还加上了限定个数的条件 M 。
         而且,存在依赖关系。装子节点的前提是,把其父亲节点也要装进去才行。
        
         这样的情况,感觉挺难的。
    1.   dp[ k ][ j ] 代表  对于 k 节点,收集了 j 个 其子节点的最大价值。
         是否,要采取对 叶子节点  和 非叶子节点 来进行分类讨论呢?
         不是的,更加题意的依赖关系。
         我们能得到一个共性的初始化。
         dp[ k ][ 0 ]=0;
         dp[ k ][ 1 ]=val[k];//这个是要的,只有把自己装进去了,才能装你子节点呀。
       递推公式: 
       dp[ k ][ j ] = max(  dp[ k ][ j ] , dp[ dp[k].next[i] ][ j-x ] + dp[ k ][ x ] );
     
         dp[ dp[k].next[i] ][ j-x ] 表示在 k 节点 的 某个子节点里 收集 j-x 个节点。
         dp[ k ][ x ]               表示在 k 节点 里 收集 x 个节点。
     
     
    2.   寻找根节点,我们发现,有许多的森林。那么我用0来做根节点。自然 m++;        
       
    3.   最后一个问题是如何书写这个背包了。
         for( i=1; i<= f[k].num; i++)//枚举多有少的节点。
        {
            t=f[k].next[i];
            dfs(t); //搜索,实现递归。
                  for(j=m;j>=2;j--)// 不会表达。囧... 枚举该节点能收集的个数。
              {
                  for(s=1;s<=j;s++)//枚举其该儿子节点 t 收集的个数。
                    {
                      dp[k][j]=Max(dp[k][j],dp[t][j-s]+dp[k][s]);
                    }
              }
          }
     
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 using namespace std;
     6 int n,m;
     7 struct node
     8 {
     9     int next[202];
    10     int num;
    11 }f[202];
    12 int dp[202][202];
    13 
    14 int Max(int x,int y)
    15 {
    16     return x>y? x:y;
    17 }
    18 
    19 void dfs(int k)
    20 {
    21     int i,j,t,s;
    22     dp[k][0]=0;
    23     for(i=1;i<=f[k].num;i++)//枚举每一个点
    24     {
    25         t=f[k].next[i];
    26         dfs(t);
    27         for(j=m;j>=2;j--)//枚举
    28         {
    29             for(s=1;s<=j;s++)
    30             {
    31                 dp[k][j]=Max(dp[k][j],dp[t][j-s]+dp[k][s]);
    32             }
    33         }
    34     }
    35 }
    36 
    37 int main()
    38 {
    39     int i,x;
    40     while(scanf("%d%d",&n,&m)>0)
    41     {
    42         if(n==0&&m==0)break;
    43         
    44         memset(dp,0,sizeof(dp));
    45         for(i=0;i<=200;i++) f[i].num=0;
    46 
    47         for(i=1;i<=n;i++)
    48         {
    49             scanf("%d%d",&x,&dp[i][1]);
    50             f[x].num++;
    51             f[x].next[f[x].num]=i;
    52         }
    53         m++;
    54         dfs(0);
    55         printf("%d
    ",dp[0][m]);
    56     }
    57     return 0;
    58 }

    /*
    如何保证 子节点 装进去的前提是父亲节点被装进去了。
    是更具dp[i][1]=val[i];

    在推导的过程中,虽然刚开始容量为m的每个格子不是都有val[i]的值。
    但是放入多少个,例如n,那么对于在容量为n的格子里,就一定会有val[i]的存在

    */

     
  • 相关阅读:
    POJ 1236 Network of Schools(强连通分量缩点求根节点和叶子节点的个数)
    文本编辑器vim和gedit
    Ubuntu安装tensorflow
    剑指offer——python【第29题】最小的K个数
    剑指offer——python【第30题】连续子数组的最大和
    剑指offer——python【第37题】数字在排序数组中出现的次数
    剑指offer——python【第28题】数组 中出现次数超过一半的数字
    剑指offer——python【第31题】整数1出现的次数
    剑指offer——python【第54题】字符流中第一个不重复的字符
    剑指offer——python【第40题】数组中只出现一次的数字
  • 原文地址:https://www.cnblogs.com/tom987690183/p/3395006.html
Copyright © 2011-2022 走看看