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. Bootstrap栅格系统&媒体查询

    bootstrap中几乎所有元素的盒子模型为IE下的盒模型,通俗点说就是box-sizing设置成了:border-box.   栅格系统 媒体查询 媒体查询是非常别致的"有条件的 CSS ...

  2. js-内置对象及相关语法

    1:如图(视频截取的) this指的是当前标签的对象. var ary=new Array("mark","jay","leslie"); ...

  3. 远程连接Oracle设置

    1:打开net manager:开始->程序->oracle->配置和移植工具->Net Manager 2:添加服务器名->名子自定义,一般根据项目自定义,自己知道就行 ...

  4. 手动触发dom节点事件代码

    在爬代码过程中,碰到一个稀奇古怪的问题.需要手工修改select的值,然后手动触发select的change事件,但使用网络上查到的通过trigger.onchange()事件触发都不执行,没办法,只 ...

  5. 【MySQL】通信协议

    1.TCP/IP(Transmission Control Protocol/Internet Protocol) 该通信协议套件用于连接 Internet 上的主机.在 Linux 操作系统中,TC ...

  6. MSP430之section(1)

    1 Intro The smallest unit of an object file is a section. A section is a block of code or data that ...

  7. dubbo之本地存根

    本地存根 远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 ...

  8. Arduino控制继电器模块

    一.实物图 二.例子代码 每隔5s切换断开 接通状态

  9. H5-data属性的一个问题

    关于前端存数据的问题,前面写过一个博客:前端页面存取数据 看个例子: <!DOCTYPE html> <html lang="en"> <head&g ...

  10. ESP32 开发笔记(十二)LittlevGL 添加自定义字体和物理按键

    LittlevGL 添加自定义字体获取字库 ttf 文件可以从一些网站上获取字库文件,比如请注意字体许可证 生成源文件使用 LittlevGL 提供的字库文件转换工具,将 ttf 字库文件转换为源文件 ...