算法学习系列(六十一):树形DP

目录

  • 引言
  • 一、没有上司的舞会
  • 二、树的重心
  • 三、树的最长路径
  • 四、树的中心

引言

关于这个树形 D P DP DP 代码其实都是那一套,核心还是在于思维上的难度,关键是这个思路你能不能想明白,想明白了就非常的简单,因为代码几乎长得都差不多,就是某些地方的改变罢了。刚开始学还是很难的,尤其是这种东西还会跟一些其它的算法混在一起,就很讨厌了,所以继续加油吧!


一、没有上司的舞会

标签:动态规划、树形DP、状态机模型

思路:这道题其实写了很多遍了,就是定义一个状态 f [ i ] [ j ] , ( j = 0 , 1 ) f[i][j],(j=0,1) f[i][j],(j=0,1) ,代表选/不选当前结点 i i i 的情况下,整个分支的最大值。那么状态转移方程为: f [ u ] [ 0 ] = f [ u ] [ 0 ] + ∑ m a x ( f [ j ] [ 0 ] , f [ j ] [ 1 ] ) f[u][0] = f[u][0] + \sum max(f[j][0],f[j][1]) f[u][0]=f[u][0]+max(f[j][0],f[j][1]) f [ u ] [ 1 ] = f [ u ] [ 1 ] + ∑ f [ j ] [ 0 ] f[u][1] = f[u][1] + \sum f[j][0] f[u][1]=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, INF = 0x3f3f3f3f;int n, m;
int w[N];
int h[N], e[M], ne[M], idx;
int f[N][2];
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;
}

二、树的重心

标签:dfs、树形DP

思路:虽然从代码上感觉不出来这是个 D P DP DP ,但其实 D P DP DP 就是用一个状态表示了很多的状态就叫做 D P DP DP ,这道题就是用了一个 t t t 代表包括它在内的向下子树的结点的个数,然后在每个结点中都可以求出这个值,然后求出最大的,然后向上的连通块的个数拿总的结点数减去分支的总和即可,然后找出最小的最大值即可。这里值得注意的是,没有告诉父子关系,所以我们得建无向边,同时要防止向上递归回去,这里可以用两种方式解决,第一种是在参数中传一个参数,是该结点的父亲节点,遍历分支的时候判断一下即可,第二种是用一个判重数组,访问过就不访问了,这两种都可以。

题目描述:

给定一颗树,树中包含 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, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], ne[M], idx;
bool st[N];
int ans = 2e9;void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}int dfs(int u)
{st[u] = true;int sum = 1, size = 0;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;
}

三、树的最长路径

标签:树的深度优先遍历、DP、树形DP、树的直径

思路:首先这道题要求的是树的直径,这道题跟 大臣的旅费 不同的是该题的权重不相同,且不为正整数。最初的想法就是求最长路,想着拿 s p f a spfa spfa 求,只要把判断 d i s t dist dist 的条件变了就行了,但是发现不对,因为 s p f a spfa spfa 会重复经过一个点,这个直径每个点只会经过一次,然后就是用 D i j k s t r a Dijkstra Dijkstra 求的话,好像它的性质也不适用于最长路,然后就只能用树形 D P DP DP 来求了。然后就是整体的思路就是递归每一个点,递归的值为该点向下的最大值,然后我们求出每个点多个分支中的第一、第二大点的和,然后对每个点的值求最值就是所求的答案。之所以说这道题为树形 D P DP DP ,还是因为这个 t t t 代表着是一个集合的一个最值,这是 D P DP DP 的核心。
注意的点:第一、第二大值初始化应为 0 0 0 ,因为代表着无边,如果是负的,那就不选该边,也比它大,所以这个值最小也是 0 0 0 ,代表着什么边也不选。并且因为只能向下走,跟上道题不同的是,这次使用的是第二种的判断方法。又因为不知道父子结点的关系,所以要建无向边,防止不能递归所有的点。
在这里插入图片描述

题目描述:

给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。现在请你找到树中的一条最长路径。换句话说,要找到一条路径,使得使得路径两端的点的距离最远。注意:路径中可以只包含一个点。输入格式
第一行包含整数 n。接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。输出格式
输出一个整数,表示树的最长路径的长度。数据范围
1≤n≤10000,1≤ai,bi≤n,−105≤ci≤105
输入样例:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出样例:
22

示例代码:

#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 * 2, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], w[M], ne[M], idx;
int ans = -2e9;void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}int dfs(int u, int father)
{int d1 = 0, d2 = 0;  // 最次也是0,没有路径for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;int t = dfs(j,u) + w[i];if(t >= d1) d2 = d1, d1 = t;else if(t > d2) d2 = t;	} ans = max(ans, d1 + d2);return d1;
}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, c; cin >> a >> b >> c;add(a,b,c), add(b,a,c);	}	dfs(1,-1);cout << ans << endl;return 0;
}

四、树的中心

标签:树的深度优先遍历、DP、树形DP、换根DP

思路:这道题其实跟上一道题非常的像,题目要求的就是所有结点到其它结点最近的最远距离是多少,首先我们可以跟上一道题的思路一样求出每个点向下走的最远距离,可以用一个数组存起来,然后就是求其向上走的最远距离了,然后两个取最大值,最后每个点取最小的最大值即可。前一个就不说了,就是上一题的思路,然后是求向上走的最大距离,向上走的点要么继续向上走,要么向下走,向上走就是用父结点来更新子结点,我觉得这时候的上和下就刚好反过来了,因为本来这个结点向下走和从父结点到子结点,然后子结点的向上走就是该连边加上父节点向下走的距离或者是父节点向上走的距离,只不过如果父结点向下走的最长距离中的结点有子结点,那就用第二长边即可,详情见代码。

题目描述:

给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。输入格式
第一行包含整数 n。接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。数据范围
1≤n≤10000,1≤ai,bi≤n,1≤ci≤105
输入样例:
5 
2 1 1 
3 2 1 
4 3 1 
5 1 1
输出样例:
2

示例代码:

#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 * 2, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N], p1[N], up[N];
bool is_leaf[N];void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}int dfs_d(int u, int father)
{d1[u] = d2[u] = -INF;for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;int d = dfs_d(j,u) + w[i];if(d >= d1[u]){d2[u] = d1[u], d1[u] = d;p1[u] = j;}else if(d > d2[u]){d2[u] = d;}}if(d1[u] == -INF){d1[u] = d2[u] = 0;is_leaf[u] = true;}return d1[u];
}void dfs_u(int u, int father)
{for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;if(j == p1[u]) up[j] = max(up[u], d2[u]) + w[i];else up[j] = max(up[u], d1[u]) + w[i];dfs_u(j,u);}
}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, c; cin >> a >> b >> c;add(a,b,c), add(b,a,c);}dfs_d(1,-1);dfs_u(1,-1);int res = d1[1];for(int i = 2; i <= n; ++i){if(is_leaf[i]) res = min(res, up[i]);else res = min(res, max(d1[i], up[i]));}cout << res << endl;return 0;
}

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

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

相关文章

LLM应用-prompt提示:让大模型总结生成思维导图

第一步&#xff1a;大模型生成markdown思维导图格式 例如&#xff1a;kimi 总结pdf文档案例&#xff1a; 生成的markdown格式&#xff1a; # 知识图谱的构建及应用 ## 一、知识图谱的构建 ### 1. 数据采集 - 来源&#xff1a;结构化数据库、半结构化网页、非结构化文本 - 预处…

PCIE V3.0物理层协议学习笔记

一、说明 PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准&#xff0c;它原来的名称为“3GIO”&#xff0c;是由英特尔在2001年提出的&#xff0c;旨在替代旧的PCI&#xff0c;PCI-X和AGP总线标准。 PCIe属于高速串行点对点双通道高…

8.11 矢量图层线要素单一符号使用二

文章目录 前言箭头&#xff08;Arrow&#xff09;QGis设置线符号为箭头(Arrow)二次开发代码实现 总结 前言 本章介绍矢量图层线要素单一符号中箭头&#xff08;Arrow&#xff09;的使用说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 箭头&#xff08;Arr…

证照之星是什么软件 证照之星哪个版本好用?证照之星支持哪些相机 证照之星XE免费版

许多人都需要使用证件照&#xff0c;为了满足这一需求&#xff0c;人们会使用照相机、手机、电脑等工具进行拍摄。除此之外&#xff0c;市面上还存在专门的证件照拍摄软件&#xff0c;比如证照之星。那么&#xff0c;各位小伙伴是否了解证照之星哪个版本好用&#xff0c;证照之…

如何利用3D可视化大屏提升信息展示效果?

老子云3D可视化平台https://www.laozicloud.com/ 引言 在信息爆炸的时代&#xff0c;如何有效地传达和展示信息成为了各行各业的一大挑战。传统的平面展示方式已经无法满足人们对信息展示的需求&#xff0c;3D可视化大屏应运而生&#xff0c;成为了提升信息展示效果的利器。本…

大模型相关内容的研究学习

大模型研究学习 1.大模型的“幻觉” 幻觉可以分为事实性幻觉和忠实性幻觉。 事实性幻觉&#xff0c;是指模型生成的内容与可验证的现实世界事实不一致。 比如问模型“第一个在月球上行走的人是谁&#xff1f;”&#xff0c;模型回复“Charles Lindbergh在1951年月球先驱任务…

the7主题下载,探索WordPress主题的无限可能

在数字时代&#xff0c;一个出色的网站是任何企业或个人品牌的必备。但在这个竞争激烈的网络世界中&#xff0c;如何让您的网站脱颖而出&#xff1f;答案就是 the7 —— 一款专为创造独特和视觉冲击力强的网站而设计的 WordPress 主题。 1. 无限设计可能性 the7 以其独特的设…

Linux-CentOS-7忘记密码-修改登录密码图文详解

Linux-CentOS-7忘记密码-修改登录密码图文详解 1.重启系统&#xff1a; 在登录界面&#xff0c;选择要登录的用户并点击"Power"按钮&#xff0c;然后选择"Restart"或"Reboot"重新启动系统。 在系统启动时持续按下 “e” 键进入编辑模式。 2…

谷歌 I/O 2024大会全面硬钢OpenAI;腾讯宣布旗下的混元文生图大模型;阿里巴巴技术下的AI自动视频剪辑工具

✨ 1: 谷歌 I/O 2024 谷歌 I/O 2024 发布了众多新技术&#xff0c;包括 Gemini AI、大语言模型和通用 AI 智能体等&#xff0c;全面颠覆搜索体验。 谷歌 I/O 2024发布会带来许多令人兴奋的新功能和技术创新&#xff1a; Gemini 1.5 Pro&#xff1a;一个极其强大的语言模型&am…

文献检索神器分享:一键筛选顶刊论文,还能免费下载全文!

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 信息爆炸的时代&#xff0c;文献是根本读不完。一个关键词能搜出来几万篇&#xff0c;而且有些结论还是完全相反的&#xff0c;到底该读哪些&#xff1f; 第一步的文献筛选很重…

Java面试八股之float和double的区别

Java中float和double的区别 存储空间与精度&#xff1a; double&#xff1a;占据64位&#xff08;8字节&#xff09;存储空间&#xff0c;属于双精度浮点数。它可以提供较高的精度&#xff0c;通常能够精确表示大约15到17位十进制数字&#xff0c;适合用于需要较高精度计算或…

汇凯金业:3个高效的黄金投资技巧

黄金投资中的高效技巧往往承载了许多投资前辈的智慧与经验教训&#xff0c;成为新手投资者宝贵的学习资料。历史上积累的黄金投资经验可以作为新投资者的学习榜样。 3个高效的黄金投资技巧 一、稳健的中长期投资策略 在金属投资领域虽然不乏短线交易高手&#xff0c;但新手投资…

《Fundamentals of Power Electronics》——阻抗和传递函数的图解构造

通常&#xff0c;我们可以通过观察画出近似的波德图&#xff0c;而不需要大量杂乱的代数和不可避免的相关代数错误。使用这种方法可以对电路的工作原理有很大的了解。在不同频率下&#xff0c;哪些元件主导电路响应变得很清楚&#xff0c;因此合适的近似变得很明显。可以直接得…

JVM运行时内存:程序计数器

文章目录 1. 程序计数器的作用2. 程序计数器的基本特征3. 程序计数器的问题 运行时内存整体结构如下图所示: 1. 程序计数器的作用 为了保证程序(在操作系统中理解为进程)能够连续地执行下去&#xff0c;CPU必须具有某些手段来确定下一条指令的地址。而程序计数器正是起到这种作…

C# WinForm —— 15 DateTimePicker 介绍

1. 简介 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 dtp 开头Format设置显示时间的格式&#xff0c;包含Long&#xff1a; Short&#xff1a; Time&#xff1a; Custom&#xff1a;采用标准的时间格式 还是 自定义的格式CustomFormat自定…

如何搭建本地DNS服务器

一、搭建本地DNS服务器 1.初始化设置 systemctl disable --now firewalld.service #关闭防火墙&#xff0c;并开机不自启 setenforce 0 #临时关闭selinux防火墙 vim /etc/selinux/config …

1727jsp思想政治活动Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 思想政治活动管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff…

ArcGIS软件损坏怎么修复?10.7分享

前言 我们经常ArcGIS用着用着就会出现一些莫名奇怪的情况&#xff0c;比如ArcGIS的工具箱都打&#xff0c;字体丢失等、dll文件缺失。尝试了很多方法之后没有效果的&#xff0c;我们可以对软件做修复 那么修复改如果做呢&#xff1f; 不需要卸载软件&#xff0c;直接安装deskt…

智慧安防监控EasyCVR视频汇聚管理平台视频播放花屏的原因分析及处理

智慧安防监控EasyCVR视频管理平台能在复杂的网络环境中&#xff0c;将前端设备统一集中接入与汇聚管理。国标GB28181协议视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、…

哪个牌子的超声波清洗机好?四大质量出众超声波清洗机汇众

由于科技的进步&#xff0c;超声波清洗机已经成为了家庭和专业场所不可或缺的高效清洁工具。它利用超声波波动产生的微小气泡来清洁物品表面及细缝中的污渍&#xff0c;实现深层次的清洁效果。特别是对于眼镜这样的精密物品&#xff0c;定期进行深度清洁不仅能够确保视觉的清晰…