皇宫看守 树形DP

题意/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] =(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<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.



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值