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. SQLServer外部数据导入--Excel版

    例如要在test表里插入多行数据 假设字段有: ID.Name 首先要有需要导入的数据的Excel A1 对应ID B1 对应Name 选中Excel第一行的空白处,比如C1,在工具栏的函数文本框里输 ...

  2. P3709 大爷的字符串题(50分)

    题目背景 在那遥远的西南有一所学校 /*被和谐部分*/ 然后去参加该省省选虐场 然后某蒟蒻不会做,所以也出了一个字符串题: 题目描述 给你一个字符串a,每次询问一段区间的贡献 贡献定义: 每次从这个区 ...

  3. Flutter GitLab 客户端

    F4Lab Flutter for GitLab. 欢迎参加一起完成

  4. Microsoft Azure Storage Explorer

    上周主管说,要把每次开过的发票,要下载成Pdf的文件,然后就实时的将这些发票存到云上面去. 就是这个Microsoft Azure ,微软的亲儿子. 先把代码贴上来吧,挺简单的. ##.链接账号密码 ...

  5. Assembly之instruction之Register Mode

    Assembler Code Content of ROM MOV R10,R11 MOV R10,R11 Length: One or two words Operation: Move the c ...

  6. 备份-泛函编程(23)-泛函数据类型-Monad

    泛函编程(23)-泛函数据类型-Monad http://www.cnblogs.com/tiger-xc/p/4461807.html https://blog.csdn.net/samsai100 ...

  7. https ssl 总结

    主要工作: 1)算法协商: 2)密钥交换: 3)身份认证: 4)数据通信: 1.2.3主要使用握手协议: 4使用记录协议. SSL协议可分为两层:记录协议.握手协议 SSL Record Protoc ...

  8. MySql数据库多表操作

    一.连接查询[连表查询.多表查询] 当查询结果的列来源于多张表时,需要将多张表连接成一个大的数据集,再选择合适的列返回 mysql支持三种类型的连接查询,分别为: 内连接查询(inner join) ...

  9. 【转载】使用JSONObject生成和解析json

    1. json数据类型 类型 描述 Number 数字型 String 字符串型 Boolean 布尔型 Array 数组 Object 对象 null 空值 (1)json中不区分整数.小数等类型, ...

  10. jupyter notebook主目录修改

    转自http://blog.csdn.net/c437yuyang/article/details/54836303 1.打开 cmd 输入命令 jupyter notebook --generate ...