泛化背包

泛化物品
从 by plane 747 转载
2010-08-28 21:31

对于背包里最BT的这类题,有优于树归的O(C^2)算法:

       对于物品i,枚举他的儿子s,把f[x]赋予f[s],对儿子进行动归后,返回利用

       f[x,i]=max{f[x,i],f[s,i-a[s]]+w[s]}一次求解

例题:

【题目描述】

联络完毕的noip群战士们,终于等到了集结的号角。他们蜂拥而上,前往与CCF交锋的战场。

神龟已经准备好了一辆通往战场的列车,按照他的计划,这个列车将能容纳最多C个战士,当然他希望这C个战士总战斗力最强。

不幸的是,由于组织者没有进行合理的秩序安排,战士们在通往战场的列车前挤成了一个大堆;由于时间和空间关系,神龟已经无法对战士按照战斗力重新列队,只能从这一堆人中靠前的挑选战士。

我们可以将noip群战士们挤成的一个堆抽象成一个树的模型;树的根就是列车。一个战士可以进入列车,当且仅当他到列车上的路径中的战士已经全部进入了列车。当然,神龟已经在列车上等待大家了(我们可以认为他,也就是树根,是0号节点),他可是拥有4千万战斗力的勇士呢。

现在请你帮神龟计算,他最多可以带上多少战斗力的勇士。

【输入格式】

第一行包括两个数n,C,分别代表战士的总人数和列车上能容纳的战士数。

第2~n+1行每行描述了一个战士,分别代表该战士之前的战士(树中的父节点)的编号xi,和这个战士的战斗力wi。

【输出格式】

只有一行,列车最多可以带的勇士的战斗力之和。

【输入样例】

7 5

2 2

0 1

0 4

2 1

7 1

7 6

2 2

 

【输出样例】

40000013

 

【数据范围】

对于20%的数据,1<=n,c<=50;

对于70%的数据,1<=n,c<=500;

对于全部数据,1<=n<=10000,1<=c<=500,0<=xi<=n,0<=wi<=500。

提示:对于已经在车上的神龟,他的战斗力是常量40000000并且不在数据中出现。

程序:

var
pre,next,w:array[0..10000]of longint;
f:array[0..10000,0..500]of longint;
n,i,j,c:longint;
procedure init;
var
x,y:longint;
begin
fillchar(next,sizeof(next),0);
fillchar(f,sizeof(f),0);
readln(n,c);
for i:=1 to n do
   begin
     readln(x,y);
     pre[i]:=next[x];
     next[x]:=i;
     w[i]:=y;
   end;
end;
procedure dp(x,c:longint);
var
i,j,k,s:longint;
begin
s:=next[x];
while s<>0 do
   begin
     f[s]:=f[x];
     dp(s,c-1);
     for i:=1 to c do            //由于是二维数组,循环顺序不影响
      if f[x,i]<f[s,i-1]+w[s] then
       f[x,i]:=f[s,i-1]+w[s];
     s:=pre[s];
   end;
end;
begin
assign(input,'charge.in');assign(output,'charge.out');
reset(input);rewrite(output);
init;
dp(0,c-1);
writeln(f[0,c-1]+40000000);
close(input);close(output);
end.

又短又高效,真是。。。。。

posted @ 2011-06-15 17:55  木小漾  阅读(451)  评论(0编辑  收藏  举报