• 解题:POI 2013 Triumphal arch


    题面

     二分答案,问题就转化为了一个可行性问题,因为我们不知道国王会往哪里走,所以我们要在所有他可能走到的点建造,考虑用树形DP解决(这个DP还是比较好写的,你看我这个不会DP的人都能写出来=。=)

    定义$dp[x]$表示以$x$这个点为根的子树中(不包含x)需要修建的次数(因为1号点已经修好了,最后回来不用管),那么对于每个二分出的$mid$有$dp[x]=max((sum dp[son[i]])+sons[x]-mid)$,其中$sons[i]$表示它(直接的)儿子的个数,显然对于每个点是必须先把所有儿子建好的。最后如果$dp[1]=0$说明可行

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=300005;
     6 int n,t1,t2,cnt,l,r,mid,ans;
     7 int p[N],noww[2*N],goal[2*N];
     8 int son[N],dp[N];
     9 void link(int f,int t)
    10 {
    11     noww[++cnt]=p[f];
    12     goal[cnt]=t,p[f]=cnt;
    13 }
    14 void MARK(int nde,int fth)
    15 {
    16     for(int i=p[nde];i;i=noww[i])
    17         if(goal[i]!=fth) MARK(goal[i],nde),son[nde]++;
    18 }
    19 void DFS(int nde,int fth)
    20 {
    21     int tmp=0;
    22     for(int i=p[nde];i;i=noww[i])
    23         if(goal[i]!=fth) DFS(goal[i],nde),tmp+=dp[goal[i]];
    24     dp[nde]=max(tmp+son[nde]-mid,0);
    25 }
    26 bool check(int x)
    27 {
    28     memset(dp,0xcf,sizeof dp);
    29     DFS(1,0); return !dp[1];
    30 }
    31 int main ()
    32 {
    33     scanf("%d",&n),r=n;
    34     for(int i=1;i<n;i++)
    35     {
    36         scanf("%d%d",&t1,&t2);
    37         link(t1,t2),link(t2,t1);
    38     }
    39     MARK(1,0);
    40     while(l<=r)
    41     {
    42         mid=(l+r)/2;
    43         if(check(mid)) r=mid-1,ans=mid;
    44         else l=mid+1;
    45     }
    46     printf("%d",ans);
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    Linux磁盘分区、挂载
    crond任务调度
    Form组件使用
    Django路由系统
    Django中模板简单使用
    ORM常用操作
    IO多路复用
    vscode必装插件
    Flask-RESTful扩展
    flask-caching
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9682674.html
Copyright © 2020-2023  润新知