zoukankan      html  css  js  c++  java
  • 解题: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
  • 相关阅读:
    归档模式与非归档模式之间的转换
    Cognos 常见错误解决办法
    Informatica 错误信息解决办法汇总
    转摘:解决动态列固定行月季年组合式报表
    数据库名、实例名、全局数据库名、服务名的区别
    转摘:维度与指标混合嵌入(合计)设计
    WinForm使用XML动态加载多语言
    windows中最重要的三个动态链接库及功能
    什么是.Net的异步机制(Invoke,BeginInvoke,EndInvoke) step 2
    深入理解.net服务器控件
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9679292.html
Copyright © 2011-2022 走看看