• 解题:POI 2011 Dynamite


    题面

    从零开始的DP学习系列之叁

    树形DP的基本(常见?)思路:先递归进儿子,然后边回溯边决策,设状态时常设$dp[x]$表示以$x$为根的子树中(具体分析算不算$x$这个点)的情况

    显然的二分答案,之后问题转化为用$m$个能覆盖$mid$范围的点能否覆盖所有的特殊点,用树形DP判断

    设$unc[nde]$表示以$nde$为根(包含$nde$)的子树中最远的未被覆盖的特殊点的距离,$cov[nde]$以$nde$为根(包含$nde$)的子树中最近的选出的点的距离。有两个从儿子$goal[i]$获取信息的显然的转移

    unc[nde]=max(unc[nde],unc[goal[i]]+1);
    cov[nde]=min(cov[nde],cov[goal[i]]+1);

    然后考虑对点的选择,首先如果这个点是特殊点,而且$cov[nde]>mid$,说明这个点无法被子树中的点覆盖,只能交给父亲处理,于是更新一下它的$unc$的信息,告诉它的父亲考虑这个点

    if(imp[nde]&&cov[nde]>mid) unc[nde]=max(unc[nde],0);

    接下来考虑这个点的子树中的特殊点(们)能否靠这个点解决,如果$unc[nde]+cov[nde]<=mid$说明这个子树不需要父亲管了

    if(unc[nde]+cov[nde]<=mid) unc[nde]=-inf;

    最后是考虑是否选择这个点,这里贪心考虑,只在$unc$正好等于$mid$时选择这个点

    if(unc[nde]==mid) unc[nde]=-inf,cov[nde]=0,tot++;

    注意的是根节点没有父亲,要特殊考虑

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=300005,inf=0x3f3f3f3f;
     6 int p[N],noww[2*N],goal[2*N];
     7 int imp[N],unc[N],cov[N];
     8 int n,m,t1,t2,cnt,tot,l,r,mid,ans;
     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     unc[nde]=-inf,cov[nde]=inf;
    17     for(int i=p[nde];i;i=noww[i])    
    18         if(goal[i]!=fth)
    19         {
    20             DFS(goal[i],nde);
    21             unc[nde]=max(unc[nde],unc[goal[i]]+1);
    22             cov[nde]=min(cov[nde],cov[goal[i]]+1);
    23         }
    24     if(imp[nde]&&cov[nde]>mid) unc[nde]=max(unc[nde],0);
    25     if(unc[nde]+cov[nde]<=mid) unc[nde]=-inf;
    26     if(unc[nde]==mid) unc[nde]=-inf,cov[nde]=0,tot++;
    27 }
    28 bool check(int x)
    29 {
    30     tot=0; DFS(1,0);
    31     return tot+(unc[1]>=0)<=m;
    32 }
    33 int main ()
    34 {
    35     scanf("%d%d",&n,&m),r=n;
    36     for(int i=1;i<=n;i++) 
    37         scanf("%d",&imp[i]);
    38     for(int i=1;i<n;i++)
    39     {
    40         scanf("%d%d",&t1,&t2);
    41         link(t1,t2),link(t2,t1);
    42     }
    43     while(l<=r)
    44     {
    45         mid=(l+r)/2;
    46         if(check(mid)) r=mid-1,ans=mid; 
    47         else l=mid+1;
    48     }
    49     printf("%d",ans);
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    【MyLocations】标记位置App开发体会
    iOS开发-Core Location和Map Kit
    iOS开发-轻点、触摸和手势
    iOS开发-GCD和后台处理
    iOS开发-block使用与多线程
    iOS开发-数据持久化
    iOS开发-为程序添加应用设置
    对iOS中MVC的理解
    docker
    linux shell
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9679292.html
Copyright © 2020-2023  润新知