zoukankan      html  css  js  c++  java
  • hdu1011_树形dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011

    (转)说实话,第一次做树形dp这类题目,答案参考网上做的,有点头疼,应该做多了就好了吧,凡事都是熟能生巧!    

          有 n(1<n<=100) 个山洞,每个山洞中都有一些 bug,每个山洞中都有一定的概率包含一个 brain。所有的山洞形成一棵树,现在给你 m(0<=m<=100) 个士兵,每个士兵都能消灭 20 个 bugs,并占领这个山洞,山洞的入口的编号是 1,问怎么安排士兵占领山洞才能使捕获 brain 的概率最大!

            典型的树上背包问题

            定义状态 f[u][P] 表示用 P 个士兵占领以 u 为根节点的子树所能获得的概率最大值,状态转移就是一个树形DP过程,目标状态就是 f[1][m]。

           f[u][p] = max {f[u][p], f[u][p - k] + f[v][k] };其中v是u的子节点。

           代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <cstdlib>
     6 #include <cmath>
     7 #include <set>
     8 #include <map>
     9 #include <vector>
    10 #define N 105
    11 using namespace std;
    12 
    13 vector <int> v[N];//
    14 int n, m, bug[N], brain[N], dp[N][N];/*dp[u][p]表示用 P 个士兵占领以 u 为根节点的子树所能获得的概率最大值*/  
    15 void dfsdp(int p, int pre)
    16 {
    17     for(int i = bug[p]; i <= m; i++)/*初始化,首先将dp[p][i]里面填充进brain[p],后面可以更新dp[p][i]的值*/
    18         dp[p][i] = brain[p];/*也就是说当我们有bug[p]名队员以至于更多时,我们最少可以获得brain[p]个大脑*/  
    19     int size = v[p].size(); /*num指p节点含有的支路数*/ 
    20     for(int i = 0; i < size; i++) /*一条支路一条支路遍历,也就是所谓的dfs*/  
    21     {
    22         int temp = v[p][i];
    23         if(temp == pre) /*避免死循环,节点如果是根部,就继续*/  
    24             continue;
    25         dfsdp(temp, p);/*递归解决问题,先将子节点的所能得到的最大值计算出来*/  
    26         for(int j = m; j >= bug[p]; j--)/*当队员人数一定时*/  
    27             for(int k = 1; k <= j - bug[p]; k++)/*由于p节点一定要通过,所以一定要花费bug[p]*/  
    28                 dp[p][j] = max(dp[p][j - k] + dp[temp][k], dp[p][j]);                
    29                 /*v节点就两种状态,要么选择,要么不选择,选择的话dp[p][j] = dp[p][j - k] + dp[v][k],不选择的话就不变*/ 
    30     }
    31 }
    32 int main()
    33 {
    34     int x, y;
    35     while(~scanf("%d %d", &n, &m) && (n != -1 && m != -1))
    36     {
    37         for(int i = 1; i <= n; i++)
    38         {
    39             v[i].clear();
    40             scanf("%d %d", &x, &brain[i]);
    41             bug[i] = (x + 19) / 20;
    42         }
    43         for(int i = 1; i < n; i++)
    44         {
    45             scanf("%d %d", &x, &y);
    46             v[x].push_back(y);
    47             v[y].push_back(x);
    48         }        
    49         if(m == 0){
    50             printf("0
    ");
    51             continue;
    52         }
    53         memset(dp, 0, sizeof(dp));
    54         dfsdp(1, 0);
    55         printf("%d
    ", dp[1][m]);
    56     }
    57     return 0;
    58 }
  • 相关阅读:
    SWT的TreeViewer和TableViewer的交互
    利用SVNKit进行版本库的树的导出
    使用SVNkit删除版本库的文件
    SVN中正确的add操作和delete操作
    SVNKIT一段代码的分析
    Eclipse中的SVN的冲突解决方案详解
    CSS3实现小于1px的边框(移动端)
    向左滑动删除一区域内容(移动端)
    下拉框文本框+复选(选中的显示在文本框中)
    弹性盒布局(自适应)
  • 原文地址:https://www.cnblogs.com/luomi/p/5590145.html
Copyright © 2011-2022 走看看