zoukankan      html  css  js  c++  java
  • [ SDOI 2006 ] 保安站岗

    (\)

    Description


    给出一棵 (n) 个节点以 (1) 为根的树,一个节点的覆盖半径是 (1) ,点有点权 (val_x)

    选择一些点,使得点权和最小,同时每个节点要么被选择要么被周围的点覆盖。

    • (nle 1500,0le val_xle 10^4)

    (\)

    Solution


    树形DP 的讨论。

    注意到覆盖有可能呈现出两层都没有选点的情况 (下面被子树覆盖,上面被父节点覆盖),所以状态设计要注意。

    (f[i][0/1/2]),表示节点 (i) 及其子树的覆盖代价,明确定义:

    • (0) 表示选择自己,覆盖整个子树的最小代价
    • (1) 表示第 (i) 个节点被自己的子树的根节点覆盖,不选择自己的最小代价
    • (2) 表示第 (i) 个节点被父节点覆盖,此时当前节点的所有子树都已经完成覆盖的最小代价

    转移讨论起来就很方便了。

    (0) :显然要选自己,所以所有子树选什么都合法,对每个子树累加 (min(f[v][0],f[v][1],f[v][2]))

    (2):不选自己,子树内部显然不能再向当前点提出需求,所以对子树累加 (min(f[v][0],f[v][1]))

    (1) 的转移有点意思。

    如果我们贪心的选,选择 (0) 状态最小的子树,剩下的子树都选 (1) 状态,不一定是最优的。

    因为这个 (0) 状态最小的子树,他的 (1) 状态可能会更小的多,这个差值完全能够允许另一个 (1) 状态变成 (0) 状态。

    (\)

    所以考虑替换, (yy) 出来一个比较好的写法。

    先对所有子树求出 (sum=min(f[v][0],f[v][1]))

    同时维护 (tmp=min( f[v][0]-min(f[v][0],f[v][1]) ))

    (\)

    这个 (sum) 的含义是,不考虑子树覆盖当前节点, 子树内部覆盖的最小值,可以发现其实就是 (f[u][2])

    (tmp) 的含义就是,把这个 (sum) 集合里的任意一个点不管之前选的什么,现在变成 (0) 状态的最小代价。

    如果之前求 (sum) 的时候选了一个 (0) 状态,那么这个 (tmp) 显然是 (0)

    如果之前没有选到任意一个 (0) 状态,那么这个 (tmp) 就是所有的 (1) 状态里,变成 (0) 状态的最小代价。

    所以有 (f[v][1]=f[v][2]+tmp)

    (\)

    Code


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 1510
    #define gc getchar
    #define R register
    #define inf 2000000000
    using namespace std;
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int n,m,tot,hd[N],f[N][3],val[N];
    
    struct edge{int to,nxt;}e[N<<1];
    
    inline void add(int u,int v){
      e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
    }
    
    //0: 选自己
    //1: 选子树内覆盖自己
    //2:选父节点覆盖自己
    
    void dfs(int u,int fa){
      int mn=inf;
      f[u][0]=val[u]; f[u][2]=0;
      for(R int i=hd[u],v;i;i=e[i].nxt)
        if((v=e[i].to)!=fa){
          dfs(v,u);
          f[u][0]+=min(f[v][2],min(f[v][1],f[v][0]));
          f[u][2]+=min(f[v][1],f[v][0]);
          mn=min(mn,f[v][0]-min(f[v][1],f[v][0]));
        }
        f[u][1]=f[u][2]+mn;
    }
    
    int main(){
      n=rd();
      memset(f,0x3f,sizeof(f));
      for(R int i=1,u,cnt;i<=n;++i){
        u=rd(); val[u]=rd(); cnt=rd();
        for(R int j=1,v;j<=cnt;++j){v=rd();add(u,v);add(v,u);}
      }
      dfs(1,0);
      printf("%d
    ",min(f[1][0],f[1][1]));
      return 0;
    }
    
    
  • 相关阅读:
    张硕组兽棋测试报告(整理——郑云飞)
    5.6任务进展情况(整理——郑云飞)
    5.5任务进展情况(整理——祁子梁)
    android-读取MediaProvider
    android-effect
    window下载android 最新源码
    android-mediaplayer播放
    android-基础编程-Notification
    android-基础编程-ViewPager
    android-glsurfaceview Activity框架程序
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9949197.html
Copyright © 2011-2022 走看看