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.
View Code

 

你可能感兴趣的:(more)