算法刷题day39:树形DP

目录

  • 引言
  • 一、病毒溯源
  • 二、没有上司的舞会
  • 三、生命之树
  • 四、树的重心

引言

今天写了个树形DP,就是在树上的DP,其实每道题的总体是一样的,从代码上都能看出来,其实写多了感觉就是背之前写过的代码,其实也就是别人写过的代码,这种题基本就是这,死记硬背肯定是不行的,主要是理解大概的思路,然后再现场调,继续加油吧!


一、病毒溯源

标签:树形DP、求方案

思路:就是给了一棵树,问这棵树的直径,并且求出直径最长的方案所对应的值。这道题用树形DP做就可以了,基本思路就是先递归出各个儿子的值,然后每个儿子进行比较,找最大的并且字典序较小的,然后存起来就行了。具体细节见代码。

题目描述:

病毒容易发生变异。某种病毒可以通过突变产生若干变异的毒株,而这些变异的病毒又可能被诱发突变产生第二代变异,如此继续不断变化。现给定一些病毒之间的变异关系,要求你找出其中最长的一条变异链。在此假设给出的变异都是由突变引起的,不考虑复杂的基因重组变异问题 —— 即每一种病毒都是由唯一的一种病毒突变而来,并且
不存在循环变异的情况。输入格式
输入在第一行中给出一个正整数 N,即病毒种类的总数。于是我们将所有病毒从 0 到 N−1 进行编号。随后 N 行,每行按以下格式描述一种病毒的变异情况:k 变异株1 …… 变异株k其中 k 是该病毒产生的变异毒株的种类数,后面跟着每种变异株的编号。第 i 行对应编号为 i 的病毒(0≤i<N)。题目保证病毒源
头有且仅有一个。输出格式
首先输出从源头开始最长变异链的长度。在第二行中输出从源头开始最长的一条变异链,编号间以 1 个空格分隔,行首尾不得有多余空格。如果最长链不唯一,则输出最小序列。注:我们称序列 {a1,…,an} 比序列 {b1,…,bn} “小”,如果存在 1≤k≤n 满足 ai=bi 对所有 i<k 成立,且 ak<bk。数据范围
1≤N≤104
输入样例:
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1
输出样例:
4
0 4 9 1

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e4+10, M = N;int n;
int h[N], e[N], ne[N], idx;
int f[N];
bool has_father[N];
int path[N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void dfs(int u)
{f[u] = 1;path[u] = -1;int maxid = -1;for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];dfs(j);if(maxid == -1 || f[j] > f[maxid] || f[j] == f[maxid] && j < maxid) maxid = j;}f[u] += f[maxid];path[u] = maxid;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 0; i < n; ++i){int k; cin >> k;while(k--){int b; cin >> b;add(i,b);has_father[b] = true;}}int root = 0;  // 没说明根结点是哪个while(has_father[root]) root++;dfs(root);cout << f[root] << endl;cout << root;for(int i = path[root]; i != -1; i = path[i]){cout << " " << i;}return 0;
}

二、没有上司的舞会

标签:动态规划、树形DP

思路:定义一个 f [ u ] [ 2 ] f[u][2] f[u][2] ,其中 0 0 0 代表不选该结点, 1 1 1 则代表选该节点,则我们可以从根结点递归出每个儿子的值,由此可以推出方程: f [ u ] [ 0 ] = ∑ m a x ( f [ j ] [ 0 ] , f [ j ] [ 1 ] ) f[u][0] = \sum max(f[j][0],f[j][1]) f[u][0]=max(f[j][0],f[j][1]) f [ u ] [ 1 ] = ∑ f [ j ] [ 0 ] f[u][1] = \sum f[j][0] f[u][1]=f[j][0] 然后就根据方程得出答案即可,这题跟上一个题的大体是一样的。

题目描述:

Ural 大学有 N 名职员,编号为 1∼N。他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。每个职员有一个快乐指数,用整数 Hi 给出,其中 1≤i≤N。现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。输入格式
第一行一个整数 N。接下来 N 行,第 i 行表示 i 号职员的快乐指数 Hi。接下来 N−1 行,每行输入一对整数 L,K,表示 K 是 L 的直接上司。(注意一下,后一个数是前一个数的父节点,不要搞反)。输出格式
输出最大的快乐指数。数据范围
1≤N≤6000,−128≤Hi≤127
输入样例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出样例:
5

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 6010, M = N;int n;
int w[N];
int h[N], e[M], ne[M], idx;
int f[N][2];  // f[u][0]代表该结点不选  1代表选 
bool has_father[N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++; 
}void dfs(int u)
{f[u][1] = w[u];for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];dfs(j);f[u][0] += max(f[j][0], f[j][1]);f[u][1] += f[j][0];}
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 1; i <= n; ++i) cin >> w[i];for(int i = 0; i < n - 1; ++i){int a, b; cin >> a >> b;add(b,a);has_father[a] = true;}int root = 1;while(has_father[root]) root++;dfs(root);cout << max(f[root][0], f[root][1]) << endl;return 0;
}

三、生命之树

标签:树形DP

思路:题意就是找到最大的连通块,我们可以定义一个 f [ u ] f[u] f[u] 代表包含 u u u 的最大连通块数量,思路跟 树的重心 这道题基本一样,遍历没访问过的儿子的值跟 0 0 0 比较,肯定是越大越好。因为是一个递归过程,访问过的要等没访问过的才能算值,并且如果存在向回递归的结点比当前的大,那么最大的值就是以另一个结点为根的值了,所以要用判重一下。

题目描述:

在X森林里,上帝创建了生命之树。他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。上帝要在这棵树内选出一个非空节点集 S,使得对于 S 中的任意两个点 a,b,都存在一个点列 {a,v1,v2,…,vk,b} 使得这个点列中
的每个点都是 S 里面的元素,且序列中相邻两个点间有一条边相连。在这个前提下,上帝要使得 S 中的点所对应的整数的和尽量大。这个最大的和就是上帝给生命之树的评分。经过 atm 的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于 atm 不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。输入格式
第一行一个整数 n 表示这棵树有 n 个节点。第二行 n 个整数,依次表示每个节点的评分。接下来 n−1 行,每行 2 个整数 u,v,表示存在一条 u 到 v 的边。由于这是一棵树,所以是不存在环的。树的节点编号从 1 到 n。输出格式
输出一行一个数,表示上帝给这棵树的分数。数据范围
1≤n≤105,每个节点的评分的绝对值均不超过 106。输入样例:
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5
输出样例:
8

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e5+10, M = N * 2;int n;
int w[N];
int h[N], e[M], ne[M], idx;
LL f[N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void dfs(int u, int father) // 找包含u的最大连通块 
{f[u] = w[u];for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;dfs(j,u);f[u] += max(0ll, f[j]);}
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 1; i <= n; ++i) cin >> w[i];for(int i = 0; i < n - 1; ++i){int a, b; cin >> a >> b;add(a,b), add(b,a);}dfs(1,-1);LL res = f[1];for(int i = 2; i <= n; ++i) res = max(res, f[i]);cout << res << endl;return 0;
}

四、树的重心

标签:树形DP

思路:我发现这种树形 D P DP DP 都是从根向下递归,并且都不会向回走,算是一种思维定式吧,具体解释上一题已经说了。这题就是找删除当前结点所剩的连通块的最大值最小,递归找每个结点的连通块点数,然后找最大的那个连通块,向根方向的连通块用总数把所有当前结点的连通块数一减就是了,然后找其中最大的,然后定义一个全局变量,找其中最小的。

题目描述:

给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。输入格式
第一行包含整数 n,表示树的结点数。接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。输出格式
输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。数据范围
1≤n≤105
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e5+10, M = N * 2;int n;
int h[N], e[M], ne[M], idx;
int ans = 2e9;
bool st[N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}int dfs(int u)  // 找包含u的连通块点数 
{st[u] = true;int size = 0, sum = 1;for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(st[j]) continue;int t = dfs(j);sum += t;size = max(size, t);}size = max(size, n - sum);ans = min(ans, size);return sum;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 0; i < n - 1; ++i){int a, b; cin >> a >> b;add(a,b), add(b,a);}dfs(1);cout << ans << endl; return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/795579.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机扫码获取文件怎么做?文件活码在电脑上的制作方法

现在很多人会把文件生成二维码之后&#xff0c;将二维码图片打印或者分享给其他人&#xff0c;通过扫描二维码的方式快速在手机上查看或者下载文件内容&#xff0c;从而提升文件传输的速度和效率。 制作文件活码二维码可以长期有效的扫码显示文件&#xff0c;支持多个文件存入…

如果在 Ubuntu 系统中两个设备出现两个相同的端口号解决方案

问题描述&#xff1a; 自己的移动机器人在为激光雷达和IMU配置动态指定的端口时&#xff0c;发现激光雷达和深度相机配置的 idVendor 和 idProduct 相同&#xff0c;但是两个设备都具有不同的ttyUSB号&#xff0c;如下图所示 idVendor&#xff1a;代表着设备的生产商ID,由USB设…

Linux第5课 Linux目录介绍

文章目录 Linux第5课 Linux目录介绍一、打开系统目录二、查看系统目录 Linux第5课 Linux目录介绍 系统目录就是指操作系统的主要文件存放的目录&#xff0c;目录中的文件直接影响到系统是否正常工作&#xff0c;了解这些目录的功能&#xff0c;对使用系统会有很大的帮助。 一…

c# wpf XmlDataProvider 简单试验

1.概要 2.代码 <Window x:Class"WpfApp2.Window12"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend…

NIO基础知识

在学习Netty之前先要学习一下NIO相关的知识&#xff0c;因为Netty是基于NIO搭建的一套网络编程框架。 一. NIO 基础 non-blocking io 非阻塞 IO 1. 三大组件 1.1 Channel & Buffer channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从…

Oracle 中 where 和 on 的区别

1.Oracle 中 where 和 on 的区别 on&#xff1a;会先根据on后面的条件进行筛选&#xff0c;条件为真时返回该行&#xff0c;由于on的优先级高于left join&#xff0c;所以left join关键字会把左表中没有匹配的所有行也都返回&#xff0c;然后生成临时表返回,执行优先级高于…

计算机接口(部分实验)

;实验三&#xff1a; ;*******************************; ;* 8255方式0的C口输入,A口输出 *; ;*******************************; io8255a equ 288h io8255c equ 28ah io8255 equ 28bhcode segmentassume cs:code start: mov dx, 28bH ;设8255为…

数据大屏:现代数据分析与可视化的重要工具

数据大屏&#xff1a;现代数据分析与可视化的重要工具 随着信息技术和数据分析的不断发展&#xff0c;数据大屏作为一种高效、直观的数据展示工具&#xff0c;越来越受到各行各业的青睐。数据大屏通过大屏幕媒介&#xff0c;利用先进的显示技术&#xff0c;将大量的数据和关键…

FPGA高端项目:解码索尼IMX327 MIPI相机+2路视频融合叠加,提供开发板+工程源码+技术支持

目录 1、前言2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX327 及其配置MIPI CSI RX图像 ISP 处理HLS多路视频融合叠加图像缓存HDMI输出工程…

【51单片机入门记录】RTC(实时时钟)-DS1302应用

目录 一、DS1302相关写函数 &#xff08;1&#xff09;Write&#xff3f;Ds1302 &#xff08;2&#xff09;Write&#xff3f;Ds1302&#xff3f;Byte 二、DS130相关数据操作流程及相关代码 &#xff08;1&#xff09;DS1302初始化数据操作流程及相关代码 (shijian[i]/10&…

null 和 undefined 的区别

1. 前言 null 和 undefined 的区别 &#xff1f;这是一道基础面试题 很多人都会说 null 是空&#xff0c;undefined 是未定义&#xff0c;这样回答太过于笼统。 面试官反问&#xff1a;null 是空代表没有值是吧&#xff0c;undefined 是未定义也是没有值是吧&#xff0c;都是…

20240406在Ubuntu20.04下让移远的4G模块EC200A-CN通过USB底板直接上网

20240406在Ubuntu20.04下让移远的4G模块EC200A-CN通过USB底板直接上网 2024/4/6 15:42 缘起&#xff1a;最近在调试全志H3平台在linux&#xff08;Ubuntu Core/openWRT&#xff09;下适配EC200A-CN。 以前调试移远的EC20的时候是先在Ubuntu下确认模块时好的&#xff0c;然后再开…

最新在线工具箱网站系统源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 系统内置高达72种站长工具、开发工具、娱乐工具等功能。此系统支持本地调用API&#xff0c;同时还自带免费API接口&#xff0c; 是一个多功能性工具程序&#xff0c;支持后台管理、上…

蓝凌OA单点登录实现方案:以统一身份管理提升效率与安全新举措

蓝凌OA的优势与挑战 在数字化浪潮的推动下&#xff0c;企业对于高效、安全的身份管理需求愈发迫切。蓝凌OA系统&#xff0c;以其出色的流程管理和协同办公能力&#xff0c;已经成为众多企业实现数字化转型的重要工具。然而&#xff0c;随着企业信息化建设的不断深入&#xff0…

配置vscode链接linux

1.安装 remote SSH 2.按F1 ssh ljh服务器公网ip 3. 选择保存远端host到本地 某位置 等待片刻后 4. 切换到远程资源管理器中 应该可以看到一台电脑&#xff0c;右键在当前窗口链接&#xff0c;输入你的服务器用户密码后电脑变绿说明远程连接成功 5.一定要登陆上云服务器后再…

错误:找不到或无法加载主类(vscode的解决方法)

项目场景&#xff1a; 某天&#xff0c;喵某人在敲代码的过程中&#xff0c;点击运行代码&#xff0c;突然显示找不到或无法加载主类。之前创建的java文件都可以正常运行。但新建的java文件无论是什么&#xff0c;点击运行都会显示“错误&#xff1a;找不到或无法加载主类”。 …

深入剖析:HTML页面从用户请求到完整呈现的多阶段加载与渲染全流程详解

HTML页面的加载全过程是一个涉及网络通信、文件解析、资源加载、渲染树构建、布局计算以及最终绘制等多个环节的复杂过程。以下是详细的步骤说明&#xff1a; 1. 用户输入URL并发送请求 用户在浏览器地址栏输入一个URL&#xff08;统一资源定位符&#xff09;&#xff0c;或者…

【内存泄漏】数据库连接connectionPhantomRefs内存过大

1. 问题背景 线上出现内存报警&#xff0c;内存增长曲线如下 dump内存文件&#xff0c;临时重新发布服务。后经排查发现是数据库连接池设置不合理以及mysql-connector-java 5.1.49有内存泄漏bug。以下为对此问题的分析及问题总结。 1.1 应用背景 数据库连接池&#xff1a; …

[StartingPoint][Tier1]Ignition

Task 1 Which service version is found to be running on port 80? (发现哪个服务版本在端口 80 上运行&#xff1f;) $ nmap -sV -Pn 10.129.1.27 -p 80 nginx 1.14.2 Task 2 What is the 3-digit HTTP status code returned when you visit http://{machine IP}/? (访…

【Linux篇】makefile一次形成两个可执行

首先要知道&#xff0c;正常的makefile文件&#xff0c;在执行的时候&#xff0c;遇到第一个目标文件&#xff0c;就只生成这一个 exec:exec.cgcc -o $ $^ mycmd:mycmd.cgcc -o $ $^ .PHONY:clean clean:rm -rf exec上面的makefile只会生成exec&#xff0c;因为第一次遇到的…