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. 20小时掌握网站开发(免费精品htmlcss视频教程)

    自己最近研发了一套新的htmlcss教程,并进行了授课实施,视频教程百度云下载链接如下: 视频及案例源码下载地址 本套教程视频需要安装屏幕录像专家软件才能观看,屏幕录像专家下载地址如下: 屏幕录像专家 ...

  2. C#使用wkhtmltopdf,把HTML生成PDF(包含分页)

    最近花了2天多的时间终于把HTML生成PDF弄好了.步骤如下: 1.首先是技术选型.看了好多都是收费的就不考虑了. 免费的有: jsPDF(前端生成,清晰度不高,生成比较慢) iText(严格要求ht ...

  3. SQLite 在 Android 的应用

    Android提供了创建和使用SQLite数据库的API(Application Programming Interface,应用程序编程接口). 在Android系统中,主要由类SQLiteData ...

  4. python排序sorted与sort比较 (转)

    Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列. sorted(iterable,key=None,revers ...

  5. Jsp页面中常用的EL表达式

    首先引入标签 <%@ page language="java" contentType="text/html; charset=utf-8"  pageE ...

  6. 【转】【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)

    原文地址:http://www.cnblogs.com/baiboy/p/orc5.html   阅读目录 目录 共享存储 时间一致性 互联网络(或者私有网络.心跳线) 固件.驱动.升级包的一致性 共 ...

  7. BZOJ 1715: [Usaco2006 Dec]Wormholes 虫洞 DFS版SPFA判负环

    Description John在他的农场中闲逛时发现了许多虫洞.虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前).John的每个农场有M条小路(无向边)连接着N ...

  8. Package和Activity

    Package Package 包.只是在我们的app中这个Package是唯一的,就像你身份证号码一样.在我们做app自动化时,我们就需要知道他的Package,我们知道了Package那么也就知道 ...

  9. vue.js层叠轮播

    最近写公司项目有涉及到轮播banner,一般的ui框架无法满足产品需求:所以自己写了一个层叠式轮播组件:现在分享给大家: 主要技术栈是vue.js ;javascript;jquery:确定实现思路因 ...

  10. [luogu2054 AHOI2005] 洗牌 (数论)

    传送门 Solution 我们考虑每一步牌的变化: 前半部分的牌位置*2 后半部分的牌位置*2-n-1 那么我们可以看做是\(x\times 2^m\equiv l \pmod n\) 于是求个逆元就 ...