P3174 毛毛虫

船送门

一道树状dp,在处理子问题上的做法真的就是单纯的标准dfs树状dp。从叶子节点向上枚举可以得到每个节点的最大子树,但这题的问题在于,没有给出根节点,而且每个节点都可以作为根节点。

那么我们只需要枚举每个结点作为根节点时的情况。在每种情况中,遍历与根结点相连的结点,求出以该节点为根节点的最大子树。此时我们先选定的结点可能连着多个子树,但是我们只能选择一条链,所以选择最大的两个子树进行连接,剩下的子树都只能选择一条边。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int f[300005],head[300005],n,m,tot=0,ans=0,maxx,son[300005];
struct Edge
{
    int to,nxt;
}edge[900005];

void add(int u,int v)
{
    edge[++tot].to=v;
    edge[tot].nxt=head[u];
    head[u]=tot;
}

void dfs(int u,int fa)
{
    int v,dade=0,xiaode=0;
    for(int i=head[u];i;i=edge[i].nxt)
    {
        v=edge[i].to;
        if(v!=fa)
        {
            dfs(v,u);
            if(f[v]>xiaode)
            {
                if(f[v]>dade)
                {
                  xiaode=dade;
                  dade=f[v];
                }
                else
                xiaode=f[v];
            }
            f[u]=max(f[u],f[v]+son[u]-1);
        }
    }
    ans=max(ans,xiaode+dade+son[u]-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
        son[u]++;
        son[v]++;
    }
    for(int i=1;i<=n;i++)
    f[i]=1;
    dfs(1,0);
    cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/charlesss/p/10335938.html

时间: 2024-10-20 11:45:18

P3174 毛毛虫的相关文章

P3174 [HAOI2009]毛毛虫

题目描述 对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大.例如下图左边的树(图 1 )抽出一部分就变成了右边的一个毛毛虫了(图 2 ). 输入输出格式 输入格式: 在文本文件 worm.in 中第一行两个整数 N , M ,分别表示树中结点个数和树的边数. 接下来 M 行,每行两个整数 a, b 表示点 a 和点 b 有边连接( a, b ≤ N ).你可以假定没有一对相同的 (a, b) 会出现一次以上. 输出格式: 在文本文件 worm.o

P3174 [HAOI2009]毛毛虫 题解

CSDN同步 原题链接 简要题意: 给定一棵树,求最长的 "挂链" 长度. 挂链定义为:一条链上所有节点与其相连的节点构成的生成树.(非严谨定义)(原题中是 "毛毛虫",本人以为挂链更形象) 这题有多种做法,这里给出思路,以及其中一种做法的代码. 算法一 注意到,其实我们只需要选出 "最长链",然后在最长链的两侧挂链即可. 即,先求出 树的直径 的两个端点,然后遍历一遍直径上的端点,把它们的直接连边都加入生成树中. 最后统计答案即可. 时间复杂度

【Luogu P3174 】[HAOI2009]毛毛虫

前言: 虽然很多人和我想法一样 ,但我还是不要脸地写了这题解 题目: 链接 大意: 在一棵树上取一条最长链以及它所连接的结点总共的结点个数 思路: 取链: 用树形\(DP\)就可以轻而易举的解决这个问题: \(f_x\)表示以\(x\)为根节点的树的深度 转移方程: \[f_x=max\{f_y + 1 \} (y\in son(x))\] 那么以\(x\)为根节点的树的最长链就是\(f_x\)加上次大的子树深度,下方代码区以\(ans\)来表示. 代码: void dp(int x, int

【HAOI2009】【P1307】毛毛虫

感觉相比其他树归题简单多了,不过有点绕(也许是我的思路很奇怪一.一)(这是省选题啊,就算作为T1这题也太水了,HA好弱……) 原题: 对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大.例如下图左边的树(图1)抽出一部分就变成了右边的一个毛毛虫了(图2). N≤300000 先搞出无根树,这回不枚举中间点了,说说我的奇怪的做法一.一 搞两个数组,一个是uf,表示包括自己在内的直系最大值,另一个是bf,表示x和x往下的兄弟中uf最大的一个 然后就是求

[haoi2009]毛毛虫 树形dp

这道题细节处理不少,但要AC不难: 设以i节点为根节点的子树能形成的最大的毛毛虫长度为f[i],则f[i]=max(f[j])+i节点的孩子数: 答案需要f最大和次大的两个子树合并,而且若合并的位置不是根节点,ans++: 我就是坑在了最后一点上,最后打表找到了问题: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=30

毛毛虫

项目描述:用一串小圆球组成的毛毛虫,可以拖动其头部,让毛毛虫跟随你的手指移动. 主要技术:使用UIDynamic来实现物理仿真效果,添加物理行为和碰撞行为,并两两添加附着行为,为毛毛虫的头部添加捕捉行为. #import "ViewController.h" @interface ViewController () @property (nonatomic,strong)UIDynamicAnimator *animator; @property (nonatomic,strong)N

【HAOI2009】【毛毛虫】【树形dp】

试题描述 对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大.例如下图左边的树(图 1 )抽出一部分就变成了右边的一个毛毛虫了(图 2 ). 输入数据 在文本文件 worm.in 中第一行两个整数 N , M ,分别表示树中结点个数和树的边数. 接下来 M 行,每行两个整数 a, b 表示点 a 和点 b 有边连接( a, b ≤ N ).你可以假定没有一对相同的 (a, b) 会出现一次以上. 输出数据 在文本文件 worm.out 中写入一个整

WORM Worm worm 毛毛虫爬树爬树~

对于动态规划,我也就不多说了.因为还不会, 每个题都不一样,但大致原则是一样的.抓住题意, 本题:n棵树,毛毛虫在m分钟内从p到t的路线种数,毛毛虫只可以向左右相邻位置走. 中心代码: for(i = 1; i <= m; i++) for(j = 1; j <= n; j++) dp[i][j] += dp[i-1][j-1] + dp[i-1][j+1];遍历所有可能时间点的位置的种数,最后得出m分钟t棵树的种数.原题已知0时间p位置是1.好好读题.. 原题: Worm Time Limi

[HAOI2009]毛毛虫

题目描述 对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大.例如下图左边的树(图 1 )抽出一部分就变成了右边的一个毛毛虫了(图 2 ). 输入输出格式 输入格式: 在文本文件 worm.in 中第一行两个整数 N , M ,分别表示树中结点个数和树的边数. 接下来 M 行,每行两个整数 a, b 表示点 a 和点 b 有边连接( a, b ≤ N ).你可以假定没有一对相同的 (a, b) 会出现一次以上. 输出格式: 在文本文件 worm.o