zoukankan      html  css  js  c++  java
  • HD1561The 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): 6765    Accepted Submission(s): 3978


    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
     
    Author
    8600
     
    Source
     
    Recommend
    LL
     
    分析:dp[i][j]表示以i节点的子树最多选择j个城市的最大价值
    对于i节点选择j个城市,可以从i节点的选择k个城市,从i的子节点选择j - k个城市,状态转移dp[i][j] = max{ dp[ i ][ j ], dp[ i ][ k] + dp[ son[i] ][j - k] }
    把0点作为根节点就组成了一颗树,最后所求就是dp[0][m]
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 using namespace std;
     6 const int Max = 220;
     7 struct Node
     8 {
     9     int to;
    10     int next;
    11 };
    12 Node edge[Max];
    13 int dp[Max][Max],value[Max],head[Max];
    14 int n,m,tol;
    15 void add_edge(int a, int b)
    16 {
    17     edge[tol].to = b;
    18     edge[tol].next = head[a];
    19     head[a] = tol++;
    20 }
    21 void init()
    22 {
    23     tol = 0;
    24     memset(head, -1, sizeof(head));
    25     memset(dp, 0, sizeof(dp));
    26 }
    27 void dfs(int u)
    28 {
    29     dp[u][1] = value[u];
    30     for(int i = head[u]; i != -1; i = edge[i].next)
    31     {
    32         int v = edge[i].to;
    33         dfs(v);
    34         //每次遍历完一个子节点就更新dp[u][k]
    35         //同01背包一样,dp[u][k]保存的是上一个状态所以k要从m开始逆序循环,更新
    36         //第一层循环意思就是u节点选择k(m到1)个城市的最大价值
    37         for(int k = m; k >= 1; k--)
    38         {
    39             //第二层循环的意思就是父节点可以选择的个数,因为必选自己节点所以是<;
    40             for(int j = 1; j < k; j++)
    41             {
    42                 dp[u][k] = max(dp[u][k], dp[u][j] + dp[v][k - j]);
    43                 //此时dp[u][j]存放的是访问完前一个子节点的状态,当访问完v也就是当前子节点时就要在更新一遍
    44                 //以前的选择1个,v节点就选择m - 1个,即前一个状态选择j个,这个子节点就选择k - j个
    45             }
    46         }
    47     }
    48 }
    49 int main()
    50 {
    51     while(scanf("%d%d", &n, &m) != EOF)
    52     {
    53         if(n == 0 && m == 0)
    54             break;
    55         int a;
    56         init();
    57         for(int i = 1; i <= n; i++)
    58         {
    59             scanf("%d%d", &a, &value[i]);
    60             add_edge(a, i);
    61         }
    62         value[0] = 0;
    63         m++;
    64         dfs(0);
    65         printf("%d
    ", dp[0][m]);
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串
    SPOJ
    POJ2774 Long Long Message —— 后缀数组 两字符串的最长公共子串
    POJ3261 Milk Patterns —— 后缀数组 出现k次且可重叠的最长子串
    POJ1743 Musical Theme —— 后缀数组 重复出现且不重叠的最长子串
    SPOJ
    AC自动机小结
    HDU3247 Resource Archiver —— AC自动机 + BFS最短路 + 状压DP
    POJ1625 Censored! —— AC自动机 + DP + 大数
    Herding
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5188200.html
Copyright © 2011-2022 走看看