1561:The more, The Better - hdu
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
树形依赖背包基础题
首先先讲一下泛型物品,就是这个物品并不是不变的,你给他v的花费,他给你h[v]的价值,这个大家应该很熟悉吧
然后就是树形依赖背包了,就是每个物品必须在他的父亲被选了之后才能选
一般我们用很基本的方法,就是设f[i,j]表示这颗子树用j的花费可以得到的价值,然后很容易得到一个O(n*v^2)的算法
但是如果是这样还不够好,于是就有了O(n*v)的算法
其实我们发现每个节点都是一个泛型物品,我们要做的是泛型物品的和,所以是O(v^2)的
我们有更好的做法
假设s是i的儿子我们就先给f[s]赋一个初值,强制选物品s,和f[i]合起来,这样是O(v)的,然后dfs(s),然后再O(v)求f[i]和f[s]的并
这样做就是O(n*v)的啦
1 const 2 maxn=220; 3 var 4 f:array[0..maxn,0..maxn]of longint; 5 first,last,next,a:array[0..maxn]of longint; 6 n,m,tot:longint; 7 8 procedure insert(x,y:longint); 9 begin 10 inc(tot); 11 last[tot]:=y; 12 next[tot]:=first[x]; 13 first[x]:=tot; 14 end; 15 16 function max(x,y:longint):longint; 17 begin 18 if x>y then max:=x 19 else max:=y; 20 end; 21 22 procedure dfs(x,m:longint); 23 var 24 i,j:longint; 25 begin 26 i:=first[x]; 27 while i<>0 do 28 begin 29 for j:=0 to m-1 do 30 f[last[i],j]:=f[x,j]; 31 dfs(last[i],m-1); 32 for j:=1 to m do 33 f[x,j]:=max(f[x,j],f[last[i],j-1]+a[last[i]]); 34 i:=next[i]; 35 end; 36 end; 37 38 procedure main; 39 var 40 i,x:longint; 41 begin 42 for i:=0 to n do first[i]:=0; 43 tot:=0; 44 for i:=1 to n do 45 begin 46 read(x,a[i]); 47 insert(x,i); 48 end; 49 for i:=0 to m do f[0,i]:=0; 50 dfs(0,m); 51 writeln(f[0,m]); 52 read(n,m); 53 end; 54 55 begin 56 read(n,m); 57 while n<>0 do 58 main; 59 end.