您的位置:首页 > 其它

皇宫看守 树形DP

2016-05-13 20:21 357 查看
题意/Description:

太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。 
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。 
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。 

读入/Input:

帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

输出/Output:

输入文件中数据表示一棵树,描述如下: 
第1行 n,表示树中结点的数目。 
第2行至第n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(0<i<=n),在该宫殿安置侍卫所需的经费k,该边的儿子数m,接下来m个数,分别是这个节点的m个儿子的标号r1,r2,...,rm。

对于一个n(0 < n<=1500)个结点的树,结点标号在1到n之间,且标号不重复。 



题解/solution:



     题目说的很清楚,用最少的点覆盖所有的点。题目给出的是个树,所以可以用动态规划来解决。

     给出如下定义:
F[i,0]表示i点不放,且以i为根节点的子树(包括i节点)全部被观察到;
F[i,1]表示i点不放,且以i为根节点的子树(可以不包括i节点)全部被观察到;
F[i,2]表示i点放,且以i为根节点的子树全部被观察到;

     转移如下:
1、由F[i,0]定义可知,设j为i的儿子节点,至少要有一个i的儿子节点是放置守卫的,其余的儿子节点可放可不放,但由于根节点i不放,所以其余的儿子节点如果不放的话,必须保证能被观察到,即F[j][0];所以我们需要枚举必须放置的儿子节点,即下:

  F[i,0] = min{∑(min(F[j][0],F[j,2]))+F[k,2]}

其中k为枚举的必放的儿子节点,j为除了k之外的儿子节点


2、由F[i,1]定义可知,i可以被观察到也可以不被观察到,但儿子节点必须都要被观察到,即下:

  F[i,1] =[b]∑(min(F[j,0],F[j,2])) [/b]

 
j是i的儿子节点



3、由F[i,2]定义可知,i点放置了守卫,所以对于每个儿子节点都能被观察到,取F[j,0],F[j,1],F[j,2]最小值即可,即下:
  F[i,2] = min(F[j,0],F[j,1],F[j,2]) j是i的儿子节点

对于叶节点i,F[i,0] = F[i,2] = data[i],F[i,1] = 0;

讲得已经十分详细了,剩下自己解决吧。

代码/Code:

var
son:array [0..1501,0..1501] of longint;
f:array [0..1501,1..3] of longint;
a,l:array [0..1501] of longint;
n,x,t:longint;
function min(o,p:longint):longint;
begin
if o<p then exit(o);
exit(p);
end;

procedure main(x:longint);
var
i,j,k:longint;
begin
if l[x]=0 then
begin
f[x,1]:=a[x]; f[x,3]:=a[x];
f[x,2]:=0;
exit;
end;
for i:=1 to l[x] do
main(son[x,i]);
f[x,1]:=maxlongint;
for i:=1 to l[x] do
begin
k:=0;
for j:=1 to l[x] do
if i<>j then
k:=k+min(f[son[x,j],1],f[son[x,j],3]);
f[x,1]:=min(f[x,1],k+f[son[x,i],3]);
end;
f[x,2]:=0;
for i:=1 to l[x] do
f[x,2]:=f[x,2]+min(f[son[x,i],1],f[son[x,i],3]);
f[x,3]:=a[x];
for i:=1 to l[x] do
f[x,3]:=f[x,3]+min(f[son[x,i],1],min(f[son[x,i],2],f[son[x,i],3]));
end;

procedure init;
var
i,j:longint;
d:array [0..1501] of longint;
begin
readln(n);
fillchar(d,sizeof(d),0);
for i:=1 to n do
begin
read(x,a[x],l[x]);
for j:=1 to l[x] do
begin
read(son[x,j]);
inc(d[son[x,j]]);
end;
readln;
end;
for i:=1 to n do
if d[i]=0 then
begin
t:=i;
break;
end;
end;

begin
init;
main(t);
write(min(f[t,1],f[t,3]));
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息