#(树形动规)洛谷P3174 [HAOI2009]毛毛虫(省选/NOi-)

2023-10-31 02:20

本文主要是介绍#(树形动规)洛谷P3174 [HAOI2009]毛毛虫(省选/NOi-),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大。例如下图左边的树(图 1 )抽出一部分就变成了右边的一个毛毛虫了(图 2 )。

输入格式

在文本文件 worm.in 中第一行两个整数 N , M ,分别表示树中结点个数和树的边数。

接下来 M 行,每行两个整数 a, b 表示点 a 和点 b 有边连接( a, b ≤ N )。你可以假定没有一对相同的 (a, b) 会出现一次以上。

输出格式

在文本文件 worm.out 中写入一个整数 , 表示最大的毛毛虫的大小。

输入输出样例

输入 #1复制
13 12 
1 2 
1 5 
1 6 
3 2 
4 2 
5 7 
5 8 
7 9 
7 10 
7 11 
8 12 
8 13 
输出 #1复制
11

说明/提示

40% 的数据, N ≤ 50000

100% 的数据, N ≤ 300000

问题分析:

等价于给你一棵树,找出树上的一条链,满足该链长度和该链上子链的数目之和最大!

设f[i][j]表示从i节点到j节点的最大子链数目,对于任意节点f[i][i]=c[i],c数组存储i节点的度

对于节点i和它的儿子:f[i][ai]=c[i]+c[ai]-1;

对于节点i,j链上的任意点k,f[i][j]=f[i][k]+f[k][j]-sz[k];

树形DP?我太菜了不会怎么办qwq

先推一波式子

令点权 a[i]a[i] 为该点入度,那么一条链的权值(答案)显然是 \sum a[i]a[i] (?)

然后我们发现,每条在该链中的边被多算了一次,设 ss 为该链长度,那么一共多算了 s-1s1 条边

因为答案求的是点,所以还要再 +1+1

所以真正的答案就是 \sum a[i]-(s-1)+1a[i](s1)+1

emm....好像还是有点麻烦,再化化式子

\sum a[i]-(s-1)+1 == \sum a[i]-s+2 == \sum(a[i]-1)+2a[i](s1)+1==a[i]s+2==(a[i]1)+2

根据这个式子,我们把点权全部 -11 ,那么 \sum(a[i]-1)(a[i]1) 就是选定的链的长度

然后愉快的跑两遍 dfs(bfs)dfs(bfs) 求最长路就行了,时空复杂度 O(n)O(n) (代码炒鸡好写qwq)

代码:

#include<bits/stdc++.h>
struct E{int u,nxt;}e[600001];
int p[300001],a[300001],num,mx;
inline void add(int x,int y){e[++num]=(E){y,p[x]},p[x]=num;}
inline void dfs(int fa,int s,int dis){
if(dis>mx) mx=dis,num=s;
for(int i=p[s];i;i=e[i].nxt) if(e[i].u!=fa) dfs(s,e[i].u,dis+a[s]);
}
int main(){
int n,m,x,y;
scanf("%d%d",&n,&m),memset(a,-1,sizeof(a));
for(int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x),a[x]++,a[y]++;
dfs(0,1,a[1]),mx=0,dfs(0,num,a[num]),printf("%d",mx+2);
return 0;
}

 

转载于:https://www.cnblogs.com/little-cute-hjr/p/11449457.html

这篇关于#(树形动规)洛谷P3174 [HAOI2009]毛毛虫(省选/NOi-)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/312135

相关文章

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

oracle11.2g递归查询(树形结构查询)

转自: 一 二 简单语法介绍 一、树型表结构:节点ID 上级ID 节点名称二、公式: select 节点ID,节点名称,levelfrom 表connect by prior 节点ID=上级节点IDstart with 上级节点ID=节点值 oracle官网解说 开发人员:SQL 递归: 在 Oracle Database 11g 第 2 版中查询层次结构数据的快速

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=

洛谷 凸多边形划分

T282062 凸多边形的划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 先整一个半成品,高精度过两天复习一下补上 #include <iostream>#include <algorithm>#include <set>#include <cstring>#include <string>#include <vector>#include <map>

能量项链,洛谷

解释:  环形dp问题还是考虑将环拉直,可以参考我上一篇文章:环形石子合并 [2 3 5 10 2] 3 5 10 将环拉直,[]内是一个有效的区间,可以模拟吸收珠子的过程,         如[2 3 5] <=>(2,3)(3,5)    2是头,3是中间,5是尾 len >= 3:因为最后[2 10 2]是最小的可以合并的有效区间 len <= n + 1因为[2 3

POJ 1050 To the Max(枚举+动规)

题目: http://poj.org/problem?id=1050 题解: 此题转化成一维后就相当于求最大连续子序列了,可以枚举所有的行组合,把枚举到的起始行到终止行的值按列相加存入一个一维数组。 代码: #include<cstdio>#include<cstring>int a[101][101];int value[101];int dp[101];int max(

js实现树级递归,通过js生成tree树形菜单(递归算法)

1、效果图 需求:首先这是一个数据集—js的类型,我们需要把生成一个tree形式的对象 : var data = [{ id: 1, name: "办公管理", pid: 0 },{ id: 2, name: "请假申请", pid: 1 },{ id: 3, name: "出差申请", pid: 1 },{ id: 4, name: "请假记录", pid: 2 },{ id:

洛谷P5490扫描线

0是最小的数字,将一个线段看成一个区间,对于一个矩形,从下扫到上,入边为1,而出边为-1,意思是将这个区间上的所有点加1(区间修改).把线段表示为Line[i],其中记录了l,r,h,tag,左右端点,高度,入边还是出边(1或-1) 那么每次区间修改后不为0的区间它的值可能是1,2,3或者是其它数字,这不好统计,可以将它转化一下,0是不是表示没有被覆盖过的地方,我们只要统计0的个数然后用总长减去

zm-tree-org 数据量过大时,全部展开后,根节点点击收缩,树形消失

zm-tree-org 数据量过大时,全部展开后,根节点点击收缩,树形消失 <zm-tree-orgref="tree"@on-expand="onExpand"</zm-tree-org>export default {methods: {onExpand(e, data) {<!-- 当为根节点,且根节点为闭合时 -->if (data.root === true && data.expa

25版王道数据结构课后习题详细分析 第七章 7.3树形查找

一、单项选择题 ———————————————————— ———————————————————— 解析:二叉排序树插入新结点时不会引起树的分裂组合。对二叉排序树进行中序遍历可得到有序序列。当插入的关键字有序时,二叉排序树会形成一个长链,此时深度最大。在此种情况下进行查找,有可能需要比较每个结点的关键字,超过总结点数的1/2。 正确答案: ———————————————————