zoukankan      html  css  js  c++  java
  • P3174 [HAOI2009]毛毛虫 题解

    听说考前1天发题解会rp++哦


    题目链接

    1.解题意

    给你一棵树,求树上最大的“毛毛虫”

    其中,毛毛虫的定义为:一条主链+主链所包含的所有节点所连的一条边。

    2.找思路

    容易看出是树上dp。

    树上dp最难的环节是思考dp方程。

    从叶子节点开始考虑:

    对于1个节点,很明显答案是1。

    往上一个节点,如果上面的节点不是分叉节点,此时毛毛虫的形状还是条链。答案+1

    接着扩大情况,此时,我们遇到了分叉节点。这个节点除了当前的子树之外还有其他分支,考虑分支的合并。

    当考虑到当前有分支的节点合并的问题时,我们必定已经遍历完了子树节点,自然清楚各个子树的最大毛毛虫;于是我们可以去max,加上当前节点的大小1,而其他的子树可以作为毛毛虫的“毛”,每一个其他分支可以对答案造成1的贡献。

    综合起来,我们设f[v]为包含v节点的v节点及其子树的最大毛毛虫方案。

    f[now]=max(f[v])+1+size[now]-2;其中,v是now节点的子节点,size[now]为当前节点连的边的个数,-2就是减去连向父节点的边和最大的f[v]所在的边。

    可能有人觉得此时dp方程已经搞完了吗,只差代码实现。但是我们忽略的一个问题:毛毛虫可能盘曲在子树中;

     ——来源于洛谷题解

    这种情况下,毛毛虫就只能是由:最大的f[v],次大的f[v],size-3得到。

    我们还要统计一个次大值才行。

    但是由于转移方程的定义,f[]数组不能表示这种情况,只有表示直着的才能转移。

    那么我们只需要在每个结点时统计一下答案即可。

    ans=mx0+mx1+1+max(0,size[now]-2);

    其中,mx0为最大值,mx1为次大值。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 300007
    using namespace std;
    inline int read()
    {
        int ans=0;
        char ch=getchar(),last=' ';
        while(ch>'9'||ch<'0')last=ch,ch=getchar();
        while(ch>='0'&&ch<='9')ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
        return last=='-'?-ans:ans;
    }
    int n,a,ans,hea[N],num,siz[N],u,v,m;
    int f[N];
    struct edg{
        int nex,to;
    }edge[N<<1];
    inline void add(int from,int to)
    {
        num++;
        edge[num].nex=hea[from];
        edge[num].to=to;
        hea[from]=num;
    }
    int dfs(int now,int fa)
    {
        int mx1=0,mx0=0;
        for(int i=hea[now];i;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(v==fa)continue;
            dfs(v,now);
            f[now]=max(f[now],f[v]);
            if(f[v]>mx0)mx1=mx0,mx0=f[v];
            else if(f[v]>mx1)mx1=f[v];
        }
        f[now]+=1+max(0,siz[now]-2);
        ans=max(ans,mx0+mx1+1+max(0,siz[now]-2));
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            u=read(),v=read();
            add(u,v);siz[u]++;
            add(v,u);siz[v]++;
        }
        dfs(1,0);
        printf("%d
    ",ans);
        return 0;
    }

    完结撒花

    csp2020 rp++。

  • 相关阅读:
    Android中使用WebView, WebChromeClient和WebViewClient加载网页
    Android清除本地数据缓存代码案例
    暴雪hash算法
    C++ 指向类的指针
    Qt VS Tools 的Qt Option add 不上qt版本的问题
    Dom4j完整教程详解
    java中charAt()方法的使用
    Linux环境下C++调试的三板斧
    (转载)Markdown进阶(更改字体、颜色、大小,设置文字背景色,调整图片大小设置居中)
    关于回调函数的理解
  • 原文地址:https://www.cnblogs.com/lbssxz/p/13935672.html
Copyright © 2011-2022 走看看