• 解题:JLOI 2016 侦查守卫


    题面

    经典的$cov-unc$树形dp(这词是你自己造的吧=。=)

    设$cov[i][j]$表示覆盖完$i$的子树后至少向外再覆盖$j$层的最小代价,$unc[i][j]$表示$i$的子树中还剩下至少$j$层没有覆盖时的最小代价,然后是两个数组的抵消转移什么的

    1.边界:对于每个需要覆盖的节点$i$,$unc[i][0]=cov[i][0]=cost_i$,对于不需要覆盖的节点$unc[i][0]=cov[i][0]=0$

    而对于每个点$i$,又都有$unc[i][j]=0,cov[i][j]=cost_i(j∈N^*&&j<=d)$

    2.$cov$的转移

    对于每个距离$j$,显然有$cov[i][j]+=unc[goal[i]][j]$(覆盖它当前这个子树)

    然后对于距离小于$d$的情况有$cov[i][j]=min(cov[i][j],unc[i][j+1]+cov[goal[i]][j+1])$(子树向外覆盖)

    还有我们定义的是“至少”:$cov[i][j]=min(cov[i][j],cov[i][j+1])$

    3.$unc$的转移

    显然的,有$unc[i][0]=cov[i][0]$ 

    子树的第$i-1$层被覆盖则自己的第$i$层被覆盖,同时也是注意定义里的“最少”:$unc[i][j]=min(unc[i][j]+unc[goal[i]][j-1],unc[i][j-1]$

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=500005,K=21;
     6 int p[N],noww[2*N],goal[2*N];
     7 int cst[N],imp[N],unc[N][K],cov[N][K];
     8 int n,d,m,t1,t2,cnt,ans=0x3f3f3f3f;
     9 void link(int f,int t)
    10 {
    11     noww[++cnt]=p[f];
    12     goal[cnt]=t,p[f]=cnt;
    13 }
    14 void DFS(int nde,int fth)
    15 {
    16     if(imp[nde]) unc[nde][0]=cov[nde][0]=cst[nde];
    17     for(int i=1;i<=d;i++) cov[nde][i]=cst[nde];
    18     for(int i=p[nde];i;i=noww[i])
    19         if(goal[i]!=fth)
    20         {
    21             DFS(goal[i],nde);
    22             for(int j=d;~j;j--)
    23             {
    24                 cov[nde][j]+=unc[goal[i]][j];
    25                 if(j<d)
    26                 {
    27                     cov[nde][j]=min(cov[nde][j],cov[nde][j+1]);
    28                     cov[nde][j]=min(cov[nde][j],cov[goal[i]][j+1]+unc[nde][j+1]);
    29                 }
    30             }
    31             unc[nde][0]=cov[nde][0];
    32             for(int j=1;j<=d;j++)
    33                 unc[nde][j]=min(unc[nde][j]+unc[goal[i]][j-1],unc[nde][j-1]);
    34         }
    35 }
    36 int main ()
    37 {
    38     scanf("%d%d",&n,&d);
    39     for(int i=1;i<=n;i++)
    40         scanf("%d",&cst[i]);
    41     scanf("%d",&m);
    42     for(int i=1;i<=m;i++)
    43         scanf("%d",&t1),imp[t1]=true;
    44     for(int i=1;i<n;i++)
    45     {
    46         scanf("%d%d",&t1,&t2);
    47         link(t1,t2),link(t2,t1);
    48     }
    49     DFS(1,0); 
    50     for(int i=0;i<=d;i++) 
    51         ans=min(ans,cov[1][i]);
    52     printf("%d",ans);
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    3513: [MUTC2013]idiots
    ELK+Filebeat+Kafka+ZooKeeper 构建海量日志分析平台(elk5.2+filebeat2.11)
    【python全栈开发】初识python
    SQL疑难问题
    费用分摊问题
    透过现象看本质
    关于python3round与float的四省五入精度的问题
    Win10下VSCode安装PlantUML
    安装pymssql
    ensorFlow的安装
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9842141.html
Copyright © 2020-2023  润新知