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]:因为增加了一个根节点

 #include<stdio.h>
#include<string.h>
int n,m;
int num[];
int map[][];
int dp[][];
bool vis[];
int max(int a,int b){
return a>b?a:b;
}
void dfs(int p)
{
int i,j,k;
//将p的访问置为true
vis[p]=true;
//遍历p的所有孩子
for(i=;i<=num[p];i++)
{
//t是节点p的第i个孩子
int t=map[p][i];
//如果t没被访问,dfs它
if(!vis[t]) dfs(t);
//m反向过来是保证后面的数据不影响前面的,比如当m=5时,j=m,k=2时,等式右边出现过一次dp[p][2]
//而当m=5时,j=2,k=2时, 状态转移方程等式左边出现了dp[p][2],显然,这个出现的dp[p][2]不能影响右边那个dp[p][2]
for(j=m;j>=;j--)//选择1个的状态不用更新了,就是节点本身,初始化中已经做了
{
for(k=;k<j;k++)//k表示父亲需要取的点的个数,j-k表示孩子需要取的点的个数
{
//如果有值
if(dp[t][j-k]!=-&&dp[p][k]!=-)
dp[p][j]=max(dp[p][j],dp[p][k]+dp[t][j-k]);
}
}
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m),n||m)
{
int a,b;
dp[][]=;
memset(num,,sizeof(num));
for(i=;i<=n;i++){
scanf("%d%d",&a,&b);
//初始化
dp[i][]=b;
map[a][++num[a]]=i;
}
m++;//增加一个点,森林转换成树
//初始化
for(i=;i<=n;i++){
dp[i][]=;vis[i]=;
for(j=;j<=m;j++){
dp[i][j]=-;
}
}
dfs();
printf("%d\n",dp[][m]);
}
return ;
}

没过的代码:

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

 #include <bits/stdc++.h>
const int N=2e2+;
using namespace std;
int dp[N][N],m,n;
int num[N],g[N][N];
bool vis[N]; void dfs(int r){
vis[r]=true;
for(int i=;i<=num[r];i++){
int v=g[r][i];
if(!vis[v]) dfs(v);
for(int j=m;j>=;j--){
for(int k=;k<j;k++){
//这里可以判断一下如果有值的话
if(dp[r][k]!=-&&dp[v][j-k]!=-)
dp[r][j]=max(dp[r][j],dp[r][k]+dp[v][j-k]);
}
}
}
} int main(){
freopen("in.txt","r",stdin);
memset(dp,-,sizeof(dp));
while(scanf("%d %d",&n,&m),n||m){
for(int i=;i<=n;i++){
int a,w;
cin>>a>>w;
g[a][++num[a]]=i;//存孩子 //这里写成了g[a][++num[i]]=i;
dp[i][]=w;
dp[i][]=;
}
dp[][]=;
dp[][]=;
m++;
dfs();
cout<<dp[][m]<<endl;
} return ;
}

HDU1561 The more, The Better的更多相关文章

  1. 【树形dp小练】HDU1520 HDU2196 HDU1561 HDU3534

    [树形dp]就是在树上做的一些dp之类的递推,由于一般须要递归处理.因此平庸情况的处理可能须要理清思路.昨晚開始切了4题,作为入门训练.题目都很easy.可是似乎做起来都还口以- hdu1520 An ...

  2. hiho1055/hdu1561 - 树形dp转换成背包

    题目链接 输入:一棵树,每个节点一个权值. 输出:包括1号节点在内的m个节点组成的连通分量的权值和的最大值 hdu1561和hiho1055一样,只是变换了下说法 /***************** ...

  3. hdu1561 The more, The Better (树形dp+背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...

  4. hdu1561 树形dp + 背包

    #include<cstdio> #include<cstring> #include<iostream> #define INF 999999999 using ...

  5. HDU1561 The more, The Better(树形DP)

    题目是有n个存有宝藏的城堡,攻克任何一个城堡都需要先攻克0个或其他1个城堡,问攻克m个城堡最多能得到多少宝藏. 题目给的城堡形成一个森林,添加一个超级根把森林连在一起就是树了,那么就考虑用树型DP: ...

  6. HDU-1561 The more, The Better (树形DP+分组背包)

    题目大意:给出一片森林,总共有n个点,并且都有权值.从中选出m个,使权值和最大.其中,选某个节点之前必须先选其父节点. 题目分析:给所有的树都加一个共同的权值为0的根节点,使森林变成一棵树.定义状态d ...

  7. 树形dp hdu1561

    有的堡垒攻克需要攻克另一个堡垒,形成一个森林,最多攻克m个堡垒,求获得宝物的最大价值. 1,以0做根将森林形成树: 2,用背包计算当前节点下需要攻克k个堡垒能获得的宝物最大价值,但是注意同一个根节点的 ...

  8. hdu1561(树形dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561 题意:n座城堡,每个里面都有宝物,要求在你可以攻占m个城堡得到的最多的宝物,但是如果要攻破一个城 ...

  9. hdu1561(树形背包)

    给定n,m表示n个城堡,我们可以选择攻占m个城堡.要使得价值最大 接下来n行 a b,   第i行的a b,表示攻占第i个城堡的价值为b,但需要先攻占第a个城堡 如果有多个a=0的点,那么就不是一棵树 ...

随机推荐

  1. MTD 门店统计

    DROP TABLE #MTD ' ,@endDate date = cast(getdate() as date) CREATE TABLE #MTD(bydate date) DECLARE @c ...

  2. Java基础12一IO流

    1.IO流的原理 利用数据通道实现程序和数据源之间数据的的读写操作.  2.IO流分类 输入流.输出流.字节流.字符流.节点流.过滤流  3.InputStream 字节输入流 实现类FileInpu ...

  3. 请不要继续使用VC6.0了!

    很多次和身边的同学交流,帮助同学修改代码,互相分享经验,却发现同学们依然在使用老旧的VC6.0作为编程学习的软件,不由得喊出:“请不要继续使用VC6.0了!”. VC6.0作为当年最好的IDE(集成开 ...

  4. spring中的prop、set、list、map

    props.set.list.map这些事spring配置文件中很常见的标签,下面说下各自的适用场合. props:用于键值对,建和值都为string类型. <property name=&qu ...

  5. Type inference

    Type inference refers to the automatic detection of the data type of an expression in a programming ...

  6. Ad hoc polymorphism

    与面向对象中的接口类或抽象类中定义的函数组类似: 函数的具体执行依赖与函数医用的类型. In programming languages, ad-hoc polymorphism[1] is a ki ...

  7. Fish:Linux中比bash或zsh更好用的Shell

    Fish是一个智能且用户友好的命令行shell,适用于macOS,Linux和其他家族.fish包含语法突出显示.根据你键入字符自动提示autosuggest-as-type和花式选项卡完成等功能,无 ...

  8. 使用Java生成具有安全哈希的QR码

    这是关于如何在Java中使用salt生成QR代码和安全散列字符串的分步教程. 首先,需要一个可以处理QR码的库,我决定使用Zebra Crossing("ZXing")库,因为它简 ...

  9. Coloring Flame Graphs: Code Hues

    转自:http://www.brendangregg.com/blog/2017-07-30/coloring-flamegraphs-code-type.html I recently improv ...

  10. C++引用、类型转换、类和对象(day03)

    十 C++的引用(Reference) 引用型函数参数 )将引用用于函数的参数,可以修改实参变量的值,同时也能减小函数调用的开销. )引用参数有可能意外修饰实参的值,如果不希望修改实参变量本身,可以将 ...