zoukankan      html  css  js  c++  java
  • bzoj4871 [Heoi2017]摧毁“树状图”

    刷完了去年的省选题,发现自己dp已经凉凉了。

    虽然暴力可以拿到80分的好成绩,但是正解的dp状态和转移还是没能想到,是时候补一波dp了

    这道题我们肯定是要树形dp,存的肯定就是子树某种状态的最多的联通块数,那么我们发现有这么几个因素会影响转移

    1.子树的根是否被删掉

    2.是否有一条链可以从子树中伸出去,即根连的链数是不是奇数

    3.子树中共出现了几条路径

    那么f[i][0/1(n点删不删)][0/1(能否向上扩展)][0/1/2(子树中共有几条路径)]就是我们的数组定义

    转移时我是直接让新的子树和已有的子树信息进行合并,也需要额外记录两个信息,即当前共有几棵子树和当前子树中只有1条路径时的删去根结点时的信息。

    看起来状态定义十分麻烦,但是实际只有6个状态是有用的,手动转移,理解了就比较简单。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #define N 100500
     7 using namespace std;
     8 int e=1,head[N];
     9 struct edge{
    10     int v,next;
    11 }ed[N<<1];
    12 inline void add(int u,int v){
    13     ed[e].v=v;
    14     ed[e].next=head[u];
    15     head[u]=e++;
    16 }
    17 int T,opt,n,ans;
    18 int f[N][2][2][3];//f[i][0/1(n点删不删)][0/1(能否向上扩展)][0/1/2(子树中共有几条路径)]
    19 inline void gmax(int &x,int y){x=x>y?x:y;}
    20 inline int Max(int x,int y){return x>y?x:y;}
    21 void dfs(int x,int fa){
    22     int son=0,t=0;
    23     for(int i=head[x];i;i=ed[i].next){
    24         int v=ed[i].v;
    25         if(v==fa)continue;
    26         dfs(v,x);
    27         int f1,f2,f3,f4,f5,f6;
    28         f1=f[x][0][0][1];
    29         f2=f[x][0][0][2];
    30         f3=f[x][1][1][1]+1;
    31         f4=f[x][1][0][1]+1;
    32         f5=f[x][1][1][2]+1;
    33         f6=f[x][1][0][2]+1;
    34         gmax(f1,f[v][0][0][1]);
    35         gmax(f1,f[v][1][0][1]+1);
    36         gmax(f1,f[v][1][1][1]+1);
    37 
    38         gmax(f2,f[v][0][0][2]);
    39         gmax(f2,f[v][1][0][2]+1);
    40         gmax(f2,f[v][1][1][2]+1);
    41         gmax(f2,f[x][0][0][1]+f[v][0][0][1]-1);
    42         gmax(f2,f[x][0][0][1]+f[v][1][0][1]);
    43         gmax(f2,f[x][0][0][1]+f[v][1][1][1]);
    44 
    45         gmax(f3,f[v][1][1][1]+son);
    46         gmax(f4,f[x][1][1][1]+f[v][1][1][1]);
    47 
    48         gmax(f5,f[v][1][1][2]+son);
    49         gmax(f5,f[x][1][1][1]+f[v][0][0][1]);
    50         gmax(f5,f[x][1][1][1]+f[v][1][0][1]);
    51         gmax(f5,f[x][1][1][1]+f[v][1][1][1]); 
    52         gmax(f5,t+f[v][1][1][1]);
    53         gmax(f5,f[x][1][0][1]+f[v][1][1][1]);
    54 
    55         gmax(f6,f[x][1][0][1]+f[v][0][0][1]);
    56         gmax(f6,f[x][1][0][1]+f[v][1][0][1]);
    57         gmax(f6,f[x][1][1][2]+f[v][1][1][1]);
    58         gmax(f6,f[x][1][1][1]+f[v][1][1][2]);
    59 
    60         t=Max(t+1,son+Max(f[v][0][0][1],Max(f[v][1][0][1],f[v][1][1][1])));
    61         son++;
    62 
    63         f[x][0][0][1]=f1;
    64         f[x][0][0][2]=f2;
    65         f[x][1][1][1]=f3;
    66         f[x][1][0][1]=f4;
    67         f[x][1][1][2]=f5;
    68         f[x][1][0][2]=f6;
    69     }
    70     gmax(f[x][1][1][1],son);
    71 }
    72 inline void init(){
    73     e=1;
    74     for(int i=1;i<=n;++i)
    75         memset(f[i],0,sizeof f[i]),head[i]=0;
    76 }
    77 inline int read(){
    78     int a=0;char ch=getchar();
    79     while(ch<'0'||ch>'9')ch=getchar();
    80     while(ch>='0'&&ch<='9')a=a*10+(ch^48),ch=getchar();
    81     return a;
    82 }
    83 int main(){
    84     scanf("%d%d",&T,&opt);
    85     while(T--){
    86         n=read();
    87         init();
    88         for(int i=1;i<=opt;++i)read(),read();
    89         for(int i=1,u,v;i<n;++i){
    90             u=read();v=read();
    91             add(u,v);add(v,u);
    92         }
    93         dfs(1,0);
    94         ans=Max(f[1][0][0][2],Max(f[1][1][0][2],f[1][1][1][2]));
    95         printf("%d
    ",ans);
    96     }
    97     return 0;
    98 }
    View Code
  • 相关阅读:
    进程间通信(管道和有名管道)
    BAT面试需要什么样的程序员?
    深入剖析Redis系列: Redis哨兵模式与高可用集群
    七大进程间通信和线程同步
    详解Redis 的持久化机制--RDB和AOF
    大型网站技术架构演进
    Coding Standard(编程规范)
    @RequestBody,415Unsupported Media Type错误
    排序算法
    单例设计模式
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/8638839.html
Copyright © 2011-2022 走看看