泛化背包
对于背包里最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.
又短又高效,真是。。。。。