• HDU 1561 树形DP背包问题


    这是自己第一道背包上树形结构问题,不是很理解这个概念的可以先看看背包九讲

    自己第一次做,看了一下别人的思路,结合着对简单背包问题的求解方式自己一次AC了还是有点小激动的

    题目大意是:

    攻克m个城市,每个城市都有对应数量的宝贝,攻克某一个城市必须保证其对应的某一个特定城市已经被攻克,希望得到最多数量的宝贝

    很容易根据题目画出一个对应关系的树形结构,每个节点都有一个对应的宝物的数量

    我们用dp[i][j]存 i 号节点它下方子树中 有 j 个城市被攻克时得到的宝物最大数量 , 此时的 i 号是没有被攻克的!

    然后通过dfs自底向上更新

     1 /*
     2         总的u下方子树攻克了j个城市,为当前v姿势分配k个城市攻克
     3         添加当前v包含了攻克k-1个子树的城市,要添加子树v必须
     4         同时保证v被攻克,所以加上的是dp[v][k-1] + val[v]
     5         */
     6         for(int j = m ; j>=1 ; j--){
     7             for(int k = j ; k>0 ; k--){
     8                 dp[u][j] = max(dp[u][j] , dp[u][j-k] + dp[v][k-1] + val[v]);
     9             }
    10         }

    这里可以理解为当根节点u下方有 j 个城市被攻克时, 若有 k 个城市的攻克来自v的子树, 那么v必然要被攻克 , val[v],不然其下方的城市不能攻克

    除去v还有 k -1个v节点对应子树中的城市要攻克 ,也就是 dp[v][k-1]

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int N = 205;
     6 
     7 int dp[N][N] , val[N] , first[N] , k;
     8 
     9 struct Edge{
    10     int y , next;
    11 }e[N];
    12 
    13 void add_edge(int x , int y)
    14 {
    15     e[k].y = y , e[k].next = first[x];
    16     first[x] = k++;
    17 }
    18 
    19 void dfs(int u , int m)
    20 {
    21     for(int i=first[u] ; i!=-1 ; i=e[i].next){
    22         int v = e[i].y;
    23         dfs(v , m);
    24         /*
    25         总的u下方子树攻克了j个城市,为当前v姿势分配k个城市攻克
    26         添加当前v包含了攻克k-1个子树的城市,要添加子树v必须
    27         同时保证v被攻克,所以加上的是dp[v][k-1] + val[v]
    28         */
    29         for(int j = m ; j>=1 ; j--){
    30             for(int k = j ; k>0 ; k--){
    31                 dp[u][j] = max(dp[u][j] , dp[u][j-k] + dp[v][k-1] + val[v]);
    32             }
    33         }
    34     }
    35 }
    36 
    37 int main()
    38 {
    39    // freopen("a.in" , "r" , stdin);
    40     int n , m , a , b;
    41     while(scanf("%d%d" , &n , &m) , n||m)
    42     {
    43         memset(first , -1 , sizeof(first));
    44         k = 0;
    45         for(int i=1 ; i<=n ; i++)
    46         {
    47             scanf("%d%d" , &a , &b);
    48             add_edge(a , i);
    49             val[i] = b;
    50         }
    51         memset(dp , 0 , sizeof(dp));
    52         dfs(0 , m);
    53 
    54         printf("%d
    " , dp[0][m]);
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    树-构建二叉树
    爬虫-scrapy框架详解(17)
    How to identify the HBA cards/ports and WWN in Linux
    NetBackup常用网络端口整理
    keepalived+MySQL实现高可用
    nginx配置https双向验证(ca机构证书+自签证书)
    systemd设置nginx开机自启动
    Keepalived+Nginx搭建主从高可用并带nginx检测
    windows 挂在EMC 存储
    linux时间同步,ntpd、ntpdate
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4231865.html
Copyright © 2020-2023  润新知