• HDU


    先上题目:

    The more, The Better

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


    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了,因为这有可能是一个森林,所以我们将一开始就可以攻占的城堡作为0号节点的孩子,这样就可以将一个森林转化成一棵树了,然后对于每一个节点,因为它的孩子的组合有多种,同时孩子的孩子也会影响它们,所以这个问题可以转化为有依附的背包问题,每一个节点作为原件,它的孩子们作为附件,然后对孩子们跑一遍01背包,这样就可以用孩子的属性求出整棵子树的属性,然后一层一层地想向上推,最终就可以得到结果了。
      状态转移方程:dp[r][j]=max{dp[r][j],dp[r][j-k]+dp[ver[r][i]][k]} 其中r代表以r为根节点的子树;j为容量为j的背包,这里的意思是以r为根节点的子树一共取j个节点;k的意思是从r的第i个孩子的子树那里挑k个节点,ver[r][i]代表r的第i个孩子的标号;dp[r][j]的意思是从以r为根的子树取j个节点的最大价值是多少。
      代码那里有一个地方需要注意的,就是k不可以等于j,因为j是从一棵子树取的节点数,只要j>0,那么j里面一定要包含根节点,k==j的意思就是在不取根节点的情况下在子树上取j个节点,这不合题意。
     
    上代码:
     
     1 #include <cstdio>
     2 #include <cstring>
     3 #define max(x,y) (x >= y ? x : y)
     4 #define MAX 202
     5 using namespace std;
     6 
     7 int ver[MAX][MAX];
     8 int dp[MAX][MAX];
     9 int count[MAX];
    10 int v[MAX];
    11 int n,m;
    12 
    13 void reset(){
    14     memset(ver,0,sizeof(ver));
    15     memset(dp,0,sizeof(dp));
    16     memset(count,0,sizeof(count));
    17     memset(v,0,sizeof(v));
    18 }
    19 
    20 void dfs(int r){
    21     for(int i=0;i<count[r];i++){
    22         dfs(ver[r][i]);
    23     }
    24     dp[r][1]=v[r];
    25     for(int i=0;i<count[r];i++){
    26         int t=ver[r][i];
    27         for(int j=m;j>1;j--){
    28             for(int k=1;k<j;k++){
    29                 /** k不能等于j,因为k==j的意思就是以r为子树的树上取除去根节点以外的节点一共j个,但是因为如果不去r的话,就无法取它的孩子,所以k!=j **/
    30                 dp[r][j]=max(dp[r][j],dp[r][j-k]+dp[t][k]);
    31             }
    32         }
    33     }
    34 }
    35 
    36 int main()
    37 {
    38     //freopen("data.txt","r",stdin);
    39     while(scanf("%d %d",&n,&m),(n+m)){
    40         reset();
    41         for(int i=1;i<=n;i++){
    42             int a;
    43             scanf("%d",&a);
    44             scanf("%d",&v[i]);
    45             ver[a][count[a]]=i;
    46             count[a]++;
    47         }
    48         m++;
    49         dfs(0);
    50         printf("%d
    ",dp[0][m]);
    51     }
    52     return 0;
    53 }
    1561
     
  • 相关阅读:
    2018 蓝桥杯省赛 B 组模拟赛(一)-年龄
    在win10系统下安装和卸载Ubuntu系统(为了搞双系统)的各种办法
    2018 CCPC 中国大学生程序设计竞赛-网络选拔赛 1004(D题 )Find Integer(三角函数+费马大定理)
    HDU(杭州电子科技大学) 2614 Beat (BFS写法)
    SQL server用到的SQL语句备份下
    【SQL Server】SQL触发器经验详解
    SQL SERVER 语句大全
    sqlserver 触发器实例代码
    触发器deleted 表和 inserted 表详解
    SQL server触发器中 update insert delete 分别给写个例子被。
  • 原文地址:https://www.cnblogs.com/sineatos/p/3585466.html
Copyright © 2020-2023  润新知