• 皇宫看守 树形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.
    



  • 相关阅读:
    Windows8 游戏开发教程开篇
    IPAD 游戏开发方案,windows开发
    谈一谈 Windows 8 的软件开发架构
    html5 大家一起来瞅吧瞅吧
    silverlight5中CLGF的推进
    html5 游戏界面问题
    挑战SVN,最纯洁的SVN客户端计划
    章鱼哥的暴走,HTML5也开始了
    MySQL的常用操作!
    两种屏蔽鼠标右键的方法
  • 原文地址:https://www.cnblogs.com/zyx-crying/p/9319708.html
Copyright © 2020-2023  润新知