• 【Luogu P3174 】[HAOI2009]毛毛虫


    前言:

    虽然很多人和我想法一样 ,但我还是不要脸地写了这题解

    题目:

    链接

    大意:

    在一棵树上取一条最长链以及它所连接的结点总共的结点个数

    思路:

    取链:

    用树形(DP)就可以轻而易举的解决这个问题:

    (f_x)表示以(x)为根节点的树的深度

    转移方程:

    [f_x=max{f_y + 1 } (yin son(x)) ]

    那么以(x)为根节点的树的最长链就是(f_x)加上次大的子树深度,下方代码区以(ans)来表示。

    代码:

    void dp(int x, int root)
    {
    	f[x] = 1;
    	int maxn = 0, lown = 0; //最大 与 次大
    	for (int i = head[x]; i; i = next[i])
    	{
    		int y = to[i];
    		if (y == root) continue;
    		dp(y, x);
    		if(f[y] > lown)
    		{
    			if(f[y] > maxn) lown = maxn, maxn = f[y];
    			else lown = f[y];
    		}
    		f[x] = max(f[x], f[y] + 1);
    	}
    	ans = max(ans, f[x] + lown);
    }
    
    

    链所连接的结点:

    也就是说只用加上周边的结点就可以了,不用再递归下去。

    那我们先在( exttt{main()})里记录每个节点的儿子个数

    然后递归就可以直接加上去就可以惹!

    代码:

    void dp(int x, int root)
    {
    	f[x] = 1;
    	int num = 0;
    	int maxn = 0, lown = 0;
    	for (int i = head[x]; i; i = next[i])
    	{
    		int y = to[i];
    		if (y == root) continue;
    		dp(y, x);
    		if(f[y] > lown)
    		{
    			if(f[y] > maxn) lown = maxn, maxn = f[y];
    			else lown = f[y];
    		}
    		f[x] = max(f[x], f[y] + son[x] - 1);  //减1是因为父结点也算进去了
    	}
    	ans = max(ans, lown + maxn + son[x] - 1);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; i++)
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		ADD(x, y);
    		ADD(y, x);
    		son[x] ++, son[y] ++;
    	}
    	dp(1, 0);
    	printf("%d", ans);
        return 0;
    }
    
    

    (CSP.rp++)

  • 相关阅读:
    [NOIP2018-普及组] 对称二叉树
    UVA1637 【纸牌游戏 Double Patience】
    [SHOI2002]滑雪-题解
    题解 CF1437E 【Make It Increasing】
    题解 P4331 【[BalticOI 2004]Sequence 数字序列】
    NOIp 2020游记
    题解 P3825 【[NOI2017]游戏】
    题解 P6453 【[LNOI2014]LCA】
    题解 P6453 【[COCI2008-2009#4] F】
    题解 P5779 【[CTSC2001]聪明的学生】
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/12001305.html
Copyright © 2020-2023  润新知