2011.8.26 21:59
题目:有向树K中值问题
背景:NOIP算法复习试题书
级别:NOIP
难度:3.4
算法:树形动态规划+记忆化搜索
数据结构:多叉树转二叉树
做题时间:90分钟
编程任务:给定一棵有向树T,树T
中每个顶点u都有一个权w(u);树的每条边(u,v)也都有一个
非负边长d(u,v)。有向树T的每个顶点u 可以看作客户,其服务需求量为w(u)。每条边(u,v)的边长d(u,v)
可以看作运输费用。如果在顶点u 处未设置服务机构,则将顶点u 处的服务需求沿有向树的边(u,v)转移到顶点v
处服务机构需付出的服务转移费用为w(u)*d(u,v)。树根处已设置了服务机构,现在要在树T中增设k处服务机构,使得整棵树T
的服务转移费用最小。对于给定的有向树T,编程计算在树T中增设k处服务机构的最小服务转移费用。
一开始想的是二维的状态f[t,k]表示节点t分到了k个设置服务机构任务,但是发现有一个服务转移费用,它会根据距离的变化而变化,而假如说同样是t号节点分到了k个服务机构,那么如果t号节点不设置服务机构,那么他的服务转移费用要找到v(v号点指与t号点间接或直接相连并且设置了服务机构)号点,但是v号点也是不确定位置的,状态表示不完全,所以要加设一维表示离t号点最近的v号点,那么这样f[t,p,k]:=min(Σdfs(son[t],p,k)+dis[t,p]*tree[t].data{t号节点不设置服务机构}
,
Σdfs(son[t],t,k-1) {在t号点设置服务机构}
)
.
服务转移费用可以先用Floyd预处理好.
===========================================================
代码:
type
tre=record
l,r,f,d,data:longint;
end;
//==========================================
var
f:array[-5..200,-1..200,-1..200]
of longint;
map:array[0..200,0..200]
of longint;
tree:array[0..2000] of
tre;
ans,n,m:longint;
//==========================================
function min(x,y:longint):longint;
begin
if x<y then
exit(x)
else
exit(y);
end;
//==========================================
procedure build(now,d,f,data,t:longint);{递归建树方法}
begin
if (tree[t].l=-1) and
(t=f) then
begin
tree[t].l:=now;
tree[now].data:=data;
tree[now].f:=f;
tree[now].d:=d;{儿子到父亲节点的距离}
exit;
end;
if
(tree[t].l<>-1) and (t=f)then
begin
build(now,d,f,data,tree[t].l);
exit;
end;
if (tree[t].r=-1) and
(t<>f) then
begin
tree[t].r:=now;
tree[now].data:=data;
tree[now].f:=f;
tree[now].d:=d;
exit;
end;
if
(tree[t].r<>-1) and
(t<>f) then
begin
build(now,d,f,data,tree[t].r);
exit;
end;
end;
//==========================================
procedure init;
var
td,tf,tdata,i:longint;
begin
fillchar(tree,sizeof(tree),255);
fillchar(map,sizeof(map),5);
readln(n,m);
for i:=1 to n do
begin
readln(tdata,tf,td);
//
build(i,td,tf,tdata,tf);{递归建树方法}
if tree[tf].l=-1 then{非递归O(1)建树方法}
begin
tree[tf].l:=i;
tree[i].data:=tdata;
tree[i].d:=td;
tree[i].f:=tf;
end
else
begin
tree[i].r:=tree[tf].l;
tree[tf].l:=i;
tree[i].data:=tdata;
tree[i].d:=td;
tree[i].f:=tf;
end;
map[i,tf]:=td;
end;
end;
//==========================================
procedure floyd;{Floyd预处理服务转移费用}
var
i,j,k:longint;
begin
for k:=0 to n do
for
i:=0 to n do
for j:=0 to n do
if (i=j) or (j=k) or (k=i)
then continue
else
map[i,j]:=min(map[i,j],map[i,k]+map[k,j]);
end;
//==========================================
function dfs(t,jin,k:longint):longint;
var
temp,i:longint;
begin
if
f[t,jin,k]<f[-1,0,0] then
exit(f[t,jin,k]);{记忆化搜索}
for i:=0 to k
do{t号节点不设置服务机构}
begin
temp:=0;
if tree[t].l<>-1
then inc(temp,dfs(tree[t].l,jin,i));
if tree[t].r<>-1
then inc(temp,dfs(tree[t].r,jin,k-i));
if
temp+map[t,jin]*tree[t].data<f[t,jin,k] then
f[t,jin,k]:=temp+map[t,jin]*tree[t].data;
end;
for i:=0 to k-1
do{t号节点设置服务机构}
begin
temp:=0;
if tree[t].l<>-1
then inc(temp,dfs(tree[t].l,t,i));
if tree[t].r<>-1
then inc(temp,dfs(tree[t].r,jin,k-1-i));
if temp<f[t,jin,k] then
f[t,jin,k]:=temp;
end;
exit(f[t,jin,k]);
end;
//==========================================
procedure main;
var
i:longint;
begin
floyd;
fillchar(f,sizeof(f),100);
f[0,0,m]:=0;
ans:=dfs(tree[0].l,0,m);
writeln(ans);
end;
//==========================================
begin
//assign(output,'c:\in.txt');
rewrite(output);
// assign(input,'c:\out.txt');
reset(input);
assign(input,'kmt.in');
reset(input);
assign(output,'kmt.out');
rewrite(output);
init;
main;
close(input);
close(output);
end.
加载中,请稍候......