zoukankan      html  css  js  c++  java
  • [51nod] 1378 夹克老爷的愤怒 #树形DP

    1378 夹克老爷的愤怒

    基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
     
    夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租。
    夹克老爷很愤怒,他决定派家丁常驻村中进行镇压。
    诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来。
    家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄。
    夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?

    Input
    第1行:2个数N, K中间用空格分隔(1<= N <= 100000, 0 <= K <= N)。
    之后N-1行:每行2个数S, E中间用空格分隔,表示编号为S的村庄同编号为E的村庄之间有道路相连。(0 <= S, E < N)。
    Output
    输出一个数说明要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?
    Input示例
    4 1
    0 1
    0 2
    0 3
    Output示例
    1
    Analysis分析
     Emmmm 显然树形DP
     那么我们记录状态为 DP[ u ][ 1/0 ],u为当前点,DP[ u ][ 1 ] 表示完全覆盖 u 以及 u 的子树,DP[ u ][ 0 ] 表示完美覆盖 u 以及 u 的子树
     完美覆盖是指:所有的家丁的管辖范围都没有重叠,最大效率的利用家丁进行镇压,哪怕是没有覆盖所有点也不能有所重叠
     完全覆盖是指所有点都被覆盖,哪怕出现重叠
     其实唯一可能有的区别就是 u 这个点有没有家丁(= =当然有的时候这两个状态是一样的:如果当前点必须放置家丁的话)
     现在来确定怎么放最好
     对于一条链,显然在离端点距离为 k 的那个点放下去是最优的
     那么对于一个树上的点,如果其子树未控制的点的深度和他相差 ≥k 的话,这个点必须要放置家丁:他的父节点是没有办法控制那个最深的未控制点的
     这是必须的情况,那么还有不必须的情况:该节点其中一个儿子支系中有家丁可以控制很远的距离,以至于可以通过 u 控制到其他子节点
     这种情况就需要计算了:如果那个家丁可以控制到所有子节点中最深的未控制点,那么当前这个点就没必要设家丁了
     但是如果不行, u 必须设置。具体的判别式见代码
     我相信我的代码可读性非常好因此我就不画图了(其实是时间紧懒得画 笑)
     那么我们对于每个点就需要设置四个参数:完美覆盖最小代价,完全覆盖最小代价,u及u的子树中所能控制到的最浅的深度(buoy),u及u的子树中未控制的最深的深度(anch)
     然后就嘿嘿嘿嘿
    Code代码
     1 #include<stdio.h>
     2 #include<iostream>
     3 #define maxn 1000000
     4 using namespace std;
     5 
     6 int DP[maxn][5],buoy[maxn],anch[maxn],depth[maxn],sz[maxn],n,k;
     7 
     8 struct edge{
     9     int from,v;
    10 }e[maxn*2]; int tot,first[maxn];
    11 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; }
    12 
    13 void dfs(int u,int pre){
    14     int sum = 0; sz[u] = 1;
    15     DP[u][0] = DP[u][1] = 0; buoy[u] = 1e9; anch[u] = -1e9;
    16     for(int i = first[u];i;i = e[i].from){
    17         int v = e[i].v; if(v == pre) continue;
    18         depth[v] = depth[u]+1;
    19         dfs(v,u);
    20         sz[u] += sz[v];
    21         buoy[u] = min(buoy[u],buoy[v]);
    22         anch[u] = max(anch[u],anch[v]);
    23         sum += DP[v][0];
    24     }
    25     
    26     if(sz[u] == 1){
    27         DP[u][1] = 1;
    28         DP[u][0] = 0;
    29         if(!k) DP[u][0] = 1;
    30         buoy[u] = anch[u] = depth[u];
    31         return;
    32     }
    33     
    34 //    printf("#%d: buoy%d anch%d
    ",u,buoy[u],anch[u]);
    35     if(anch[u]-depth[u] >= k){ // Must set
    36 //        printf("#%d: Poi A
    ",u);
    37         DP[u][0] = DP[u][1] = sum+1;
    38         buoy[u] = depth[u]-k;
    39         anch[u] = buoy[u]-1;
    40     }else if(2*depth[u]-buoy[u] < anch[u]){ // Can choose
    41 //        printf("#%d: Poi B
    ",u);
    42         DP[u][0] = sum;
    43         DP[u][1] = sum+1;
    44     }else{ // Needn't
    45 //        printf("#%d: Poi C
    ",u);
    46         DP[u][0] = DP[u][1] = sum;
    47         anch[u] = buoy[u]-1;
    48     }
    49 }
    50 
    51 int main(){
    52     scanf("%d%d",&n,&k);
    53     
    54     for(int i = 1;i < n;i++){
    55         int u,v; scanf("%d%d",&u,&v);
    56         u++,v++; insert(u,v); insert(v,u);
    57     }depth[1] = 1;
    58     
    59     dfs(1,1);
    60     
    61     printf("%d
    ",DP[1][1]);
    62     
    63 //    for(int i = 1;i <= n;i++){
    64 //        printf("#%d: 0:%d 1:%d buoy:%d anch:%d
    ",i,DP[i][0],DP[i][1],buoy[i],anch[i]);
    65 //    }
    66     
    67     return 0;
    68 }
    注释代码没删
  • 相关阅读:
    手机号不能为空
    选项卡套选项卡
    可以在一个html的文件当中读取另一个html文件的内容
    价格计算
    v形 加强版
    V形
    生成100个Div
    伪元素::after和::before
    数组中的toString,toLocalString,valueOf方法有什么区别
    JavaScript toLocaleString() 方法
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7779697.html
Copyright © 2011-2022 走看看