zoukankan      html  css  js  c++  java
  • HDU1561 The more, The Better

    HDU1561 The more, The Better

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

    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

    HDU 2006-12 Programming Contest

     

     

    Recommend

    LL   |   We have carefully selected several similar problems for you:  1011 2159 2639 1203 2602 

     

    分析:

    典型的树形dp的题目。

    首先,限制条件是选择m个物品,而每个物品最多选一次,跟0-1背包的区别在于有依赖关系,那么这层依赖关系我们可以借助于一个树来解决。借助dfs,从根节点开始dfs,然后直到叶子节点,回朔的时候进行0-1背包dp。

    dp[i][j]表示以i为根节点取j个节点(包括根)的最优值

    map[i][j]表示i号节点的第j个孩子是什么

       

    num[i]表示i号节点的孩子数

         

    vis[i]==0表示i号节点没有被访问

       
           

     

    dp[i][j]=max(dp[i][j],dp[i][k]+dp[i的某个孩子节点][j-k])

    表示在父亲节点i中选k个点和在i的某个孩子中选j-k个点

    我们可以知道dp[i][1]=val[i],因为选一个点的话必须选自己 = =

    依赖关系形成森林,要先把树转换成森林才能进行树形DP

    增加一个根节点0即可

    答案即为dp[0][m+1]:因为增加了一个根节点

     1 #include<stdio.h>
     2 #include<string.h>
     3 int n,m;
     4 int num[250];
     5 int  map[250][250];
     6 int dp[250][250];
     7 bool vis[250];
     8 int max(int a,int b){
     9     return a>b?a:b;
    10 }
    11 void dfs(int p)
    12 {
    13     int i,j,k;
    14     //将p的访问置为true 
    15     vis[p]=true;
    16     //遍历p的所有孩子 
    17     for(i=1;i<=num[p];i++)
    18     {
    19         //t是节点p的第i个孩子 
    20         int t=map[p][i];
    21         //如果t没被访问,dfs它 
    22         if(!vis[t]) dfs(t);
    23         //m反向过来是保证后面的数据不影响前面的,比如当m=5时,j=m,k=2时,等式右边出现过一次dp[p][2]
    24         //而当m=5时,j=2,k=2时, 状态转移方程等式左边出现了dp[p][2],显然,这个出现的dp[p][2]不能影响右边那个dp[p][2] 
    25         for(j=m;j>=2;j--)//选择1个的状态不用更新了,就是节点本身,初始化中已经做了 
    26         {
    27             for(k=1;k<j;k++)//k表示父亲需要取的点的个数,j-k表示孩子需要取的点的个数 
    28             {
    29                 //如果有值 
    30                 if(dp[t][j-k]!=-1&&dp[p][k]!=-1)
    31                     dp[p][j]=max(dp[p][j],dp[p][k]+dp[t][j-k]);
    32             }
    33         }
    34     }
    35 }
    36 int main()
    37 {
    38     int i,j;
    39     while(scanf("%d%d",&n,&m),n||m)
    40     {
    41         int a,b;
    42         dp[0][1]=0;
    43         memset(num,0,sizeof(num));
    44         for(i=1;i<=n;i++){
    45             scanf("%d%d",&a,&b);
    46             //初始化 
    47             dp[i][1]=b;
    48             map[a][++num[a]]=i;
    49         }
    50         m++;//增加一个点,森林转换成树
    51         //初始化 
    52         for(i=0;i<=n;i++){
    53             dp[i][0]=0;vis[i]=0;
    54             for(j=2;j<=m;j++){
    55                 dp[i][j]=-1;
    56             }
    57         }
    58         dfs(0);
    59         printf("%d
    ",dp[0][m]);
    60     }
    61     return 0;
    62 }

    没过的代码:

    错误:第30行的g[a][++num[a]]=i;这里写成了g[a][++num[i]]=i; 

     1 #include <bits/stdc++.h>
     2 const int N=2e2+10; 
     3 using namespace std;
     4 int dp[N][N],m,n;
     5 int num[N],g[N][N];
     6 bool vis[N];
     7 
     8 void dfs(int r){
     9     vis[r]=true;
    10     for(int i=1;i<=num[r];i++){
    11         int v=g[r][i];
    12         if(!vis[v]) dfs(v);
    13         for(int j=m;j>=2;j--){
    14             for(int k=1;k<j;k++){
    15                 //这里可以判断一下如果有值的话 
    16                 if(dp[r][k]!=-1&&dp[v][j-k]!=-1)
    17                     dp[r][j]=max(dp[r][j],dp[r][k]+dp[v][j-k]); 
    18             }
    19         }
    20     }
    21 }
    22 
    23 int main(){
    24     freopen("in.txt","r",stdin);
    25     memset(dp,-1,sizeof(dp));
    26     while(scanf("%d %d",&n,&m),n||m){
    27         for(int i=1;i<=n;i++){
    28             int a,w;
    29             cin>>a>>w;
    30             g[a][++num[a]]=i;//存孩子 //这里写成了g[a][++num[i]]=i; 
    31             dp[i][1]=w;
    32             dp[i][0]=0;
    33         }
    34         dp[0][1]=0;
    35         dp[0][0]=0;
    36         m++;
    37         dfs(0);
    38         cout<<dp[0][m]<<endl; 
    39     }
    40     
    41     
    42     return 0;
    43 } 
  • 相关阅读:
    01.Sencha ExtJS 6
    02.Sencha ExtJS 6
    关于Jquery的delegate绑定事件无效
    细说 Form (表单)
    Rquest Request[""];Request.Form[""];Request.QueryString[""]
    一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系
    vs 调试不进入断点
    HttpWebRequest类
    C# 利用 Windows服务模板 创建、安装与卸载Windows服务
    如何搭建win10 asp开发环境安装iis10
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/7430988.html
Copyright © 2011-2022 走看看