皇宫看守 树形DP

题意/Description

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

 

读入/Input

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

 

输出/Output

输入文件中数据表示一棵树,描述如下: 
第1行 n,表示树中结点的数目。 
第2行至第n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(0 对于一个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] =(min(F[j,0],F[j,2])) 

  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

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.



 

你可能感兴趣的:(皇宫看守 树形DP)