• [HAOI2009]毛毛虫 树形DP


    题意:

    给你一棵树,从树中取出一部分满足:是一条链+一些直接连在这条链上的节点

    求节点数最多的合法取出部分。

    题解:

    其实这题还是不难?

    观察到对于任意一条链,

    只有两种情况: 一条路走到底 or  以某个点为中转

    f[x]表示从x往下走,一路走到底的包括x的最优解,

    f[x]包括x也包括father[x](将会加入它的贡献)

    观察到以某个点为中转的情况:

    倘若某条链以一个点为中转,那么这条链将无法向上产生贡献,

    若没有,则变为第一种情况,且一定可以向上产生贡献, 以点x为中转的所有链都可以通过各个儿子的搭配得到

    因此f[x]可以直接从f[son]中选取最优的来得到,

    然后用f[x]来更新ans,

    再选取儿子中的前2大,搭配起来加上x组成链,更新ans

    所以dfs一遍然后输出ans即可,复杂度O(n);

    细节还是挺多的,要注意。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 350000
     5 #define ACway 700000
     6 #define getchar() *o++
     7 char READ[10001000],*o=READ;
     8 int n,m,ans;
     9 int in[AC],f[AC];
    10 int date[ACway],Head[AC],Next[ACway],tot;
    11 /*观察到对于任意一条链,只有两种情况:
    12 一条路走到底 :以某个点为中转
    13 f[i]表示从i往下走,一条路走到底的最优解(不包括i)(非最长链)
    14 但这样并不方便。。。。因为要分的情况太多,
    15 所以f[x]表示从x往下走,一路走到底的包括x的最优解,
    16 f[x]包括x也包括father[x]
    17 观察到以某个点为中转的情况:
    18 倘若某条链以一个点为中转,那么这条链将无法向上产生贡献,
    19 若没有,则变为第一种情况。且一定可以向上产生贡献,
    20 以点x为中转的所有链都可以通过各个儿子的搭配得到,*/
    21 
    22 inline int read()
    23 {
    24     int x=0;char c=getchar();
    25     while(c > '9' || c < '0') c=getchar();
    26     while(c >= '0' && c <= '9') x=x*10+c-'0',c=getchar();
    27     return x;
    28 }
    29 
    30 inline void upmax(int &a,int b)
    31 {
    32     if(b > a) a=b;
    33 }
    34 
    35 inline void add(int f,int w)
    36 {
    37     date[++tot]=w,Next[tot]=Head[f],Head[f]=tot;
    38     date[++tot]=f,Next[tot]=Head[w],Head[w]=tot;
    39     ++in[f],++in[w];
    40 }
    41 
    42 void pre()
    43 {
    44     int a,b;
    45     n=read(),m=read();
    46     for(R i=1;i<=m;i++) 
    47     {
    48         a=read(),b=read();
    49         add(a,b);
    50     }
    51 }
    52 
    53 void dfs(int x,int fa)
    54 {
    55     int now,maxn=0,maxn2=0;
    56     f[x]=1 + in[x];//因为包括了自己,所以至少也是1 + in[x]了
    57     for(R i=Head[x] ; i ;i=Next[i])
    58     {
    59         now=date[i];
    60         if(now == fa) continue;
    61         dfs(now,x);
    62         upmax(f[x],f[now] + in[x] - 1);//因为既要加自己,又要减儿子,抵消了,所以只用加in就可以了
    63         if(f[now] > maxn)//但是由于f[now]会包括x,所以也要减掉,,,
    64         {
    65             maxn2=maxn;
    66             maxn=f[now];
    67         }
    68         else upmax(maxn2,f[now]);
    69     }
    70     upmax(ans,f[x]);
    71     upmax(ans,maxn + maxn2 + in[x] - 3);//同上,只不过多减一个儿子
    72 }//因为也会包括x,所以会重复2次
    73 
    74 void work()
    75 {
    76     dfs(1,0);//随便选个点做根节点吧
    77     printf("%d
    ",ans);
    78 //    for(R i=1;i<=n;i++) printf("%d %d
    ",i,f[i]);
    79 }
    80 
    81 int main()
    82 {
    83 //    freopen("in.in","r",stdin);
    84     fread(READ,1,10000000,stdin);
    85     pre();
    86     work();
    87 //    fclose(stdin);
    88     return 0;
    89 }
  • 相关阅读:
    hdu 3047 Zjnu Stadium(加权并查集)2009 Multi-University Training Contest 14
    hdu 5407 CRB and Candies(组合数+最小公倍数+素数表+逆元)2015 Multi-University Training Contest 10
    hdu 3635 Dragon Balls(加权并查集)2010 ACM-ICPC Multi-University Training Contest(19)
    hdu 3038 How Many Answers Are Wrong(种类并查集)2009 Multi-University Training Contest 13
    【进阶——种类并查集】hdu 1829 A Bug's Life (基础种类并查集)TUD Programming Contest 2005, Darmstadt, Germany
    hdu 1026 Ignatius and the Princess I(优先队列+bfs+记录路径)
    hdu2368Alfredo's Pizza Restaurant
    C#结课报告
    C#三个平台上的文件选择方法
    C#线程
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9097545.html
Copyright © 2020-2023  润新知