zoukankan      html  css  js  c++  java
  • HDOJ (HDU) 1561 The more, The Better (树形DP)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1561

    很明显这是个分组的有依赖的背包问题(背包问题的扩展请参考 Tianyi Cui 的背包九讲 http://love-oriented.com/pack/ )。

    构建树:若攻击城堡 a 要先攻击城堡 b,则 a 是 b 的儿子,这样构建以后是一个森林,添加一个宝物数量为0的节点作为整个森林的树根以后就是一颗树了。

    递推方程:设 dp[a][b] 表示以 a 为根节点的子树,要攻击 b 个城堡所获得的最大金钱数目。其中 a 城堡是已经攻下来的。

                   则 dp[a][b] = max( dp[a][b],  dp[a][b - k] + dp[ son(a) ][k] )  ,其中son(a) 表示 a 的儿子节点。

                   递推方程的意思是:在 a 的子节点子树中选k个点加上a 子树选 b-k 个点 与直接在 a 子树选b个点谁更优。

                  (其实背包问题或者类背包问题都有相似的递推方程)

    初始化:dp[][] 开始均初始化为0,且dp[a][1] 均初始化为节点 a 的宝物数量。

    注意细节:算法的第二层循环(代码24行)为什么b要从大到小:dp[root][b] 是由dp[root][b - k] 和 dp[tree[root][i]][k]决定,表面上看b应该从小到大循环,但是从最外层循环(代码21行)来看,

    每遍历完一个儿子,dp[root][]都被计算了一遍,在遍历下一儿子时,dp[root][b] 是由遍历上次儿子时已经计算好的dp[root][b - k] 和 dp[tree[root][i]][k]决定,若从小到大循环,则上次计算好的

    dp[root][b - k]就被覆盖了。

    废话少说,上代码:

     1 #include<iostream>
     2 #include<string>
     3 #include<vector>
     4 using namespace std;
     5 
     6 const int SIZE = 201;
     7 int max(int a, int b)
     8 {
     9     return a>b ? a:b; 
    10 }
    11 //////////////////////////////////////////////////////////////////////    
    12 vector<int> tree[SIZE];  //tree[i][j]表示节点i的第j个儿子的id
    13 bool visit[SIZE];        //树节点是都访问过
    14 int dp[SIZE][SIZE];
    15 int N,M;
    16 
    17 void dfs_dp(int root) //tree dp
    18 {
    19     if(visit[root])return;
    20     visit[root] = true;
    21     for(int i = 0; i < tree[root].size(); i++)//遍历所有儿子
    22     {
    23         if(!visit[tree[root][i]])dfs_dp(tree[root][i]); //深度优先
    24         for(int b = M; b > 1; b--) //循环变量 b 一定是从大到小!!!!!!!!!!
    25             for(int k = 1; k < b; k++)
    26             {
    27                 dp[root][b] = max(dp[root][b], dp[root][b - k] + dp[tree[root][i]][k]);
    28             }
    29     }
    30 }
    31 
    32 //将id=0的节点视为整个树的根,其宝物数量为 0;        
    33 int main()
    34 {
    35     while((cin>>N>>M) && (N || M))
    36     {
    37         //init
    38         for(int i = 0; i < SIZE; i++)
    39             tree[i].clear();
    40         memset(visit, 0, sizeof(visit)); 
    41         memset(dp, 0, sizeof(dp));  
    42         
    43         int father,val;
    44         for(int i = 1; i <= N; i++)
    45         {
    46             cin>>father>>val;
    47             tree[father].push_back(i);
    48             dp[i][1] = val;
    49         }
    50         
    51         M++; //由于添加了0号节点为树根,所以,相当于多加了个城堡,且这个城堡必须攻克
    52         dfs_dp(0);
    53         cout<<dp[0][M]<<endl;
    54     }
    55     
    56     return 1;
    57 }
    View Code

     【版权声明】转载请注明出处 http://www.cnblogs.com/TenosDoIt/archive/2013/06/15/3137679.html

     

  • 相关阅读:
    luogu P2827 蚯蚓
    CHOI1001/1002 火车进出栈问题
    hdoj4699 Editor
    反弹shell监控
    AppScan 9.0.3.6 crack
    Spectre & Meltdown Checker – CPU芯片漏洞检查脚本Linux版
    Microsoft IIS WebDav 'ScStoragePathFromUrl' Remote Buffer Overflow (CVE-2017-7269)
    Shodan新手使用指南
    The Art of Subdomain Enumeration (转)
    DDOS攻击方式总结 (转)
  • 原文地址:https://www.cnblogs.com/TenosDoIt/p/3137679.html
Copyright © 2011-2022 走看看