图论学习笔记 4 - 仙人掌图

先扔张图:


为了提前了解我们采用的方法,请先阅读《图论学习笔记 3》。

仙人掌图的定义:一个连通图,且每条边只出现在至多一个环中。

这个图就是仙人掌图。

这个图也是仙人掌图。

而这个图就不是仙人掌图了。

很容易发现,仙人掌图就是在树上连了若干条边( ≥ 1 \ge 1 1 条)。所以可以视为仙人掌图是基环树的扩展。


众所周知,我们通过想象基环树的深搜树形态解决了基环树的一些问题,所以也考虑想象仙人掌图的深搜树。

这里就直接给图了:

很容易发现以下性质:

  • 仙人掌图中,每一条回边互不相交且与环一一对应,环由回边与祖先到子孙的链构成。(这个比较显然,可以简单理解)

  • 任何一个环的 u p up up 点或者是 d n dn dn 点,其子树一定包含的是完整的环。

很容易感性理解。 u p up up 的子树一定包含所有的环点, d n dn dn 的子树一定不包含所有的环点。所以就可以证了。

  • 在每一个点的子树中,至多有一个没有遍历到其对应的 u p up up 点的 d n dn dn 点。

考虑反证法,设我们有一个点 x x x,其子树里面有两个没有遍历到其对应的 u p up up 点的 d n dn dn 点。设两个 u p up up 点为 u p 1 , u p 2 up1,up2 up1,up2,设两个 d n dn dn 点为 d n 1 , d n 2 dn1,dn2 dn1,dn2

很容易发现,两个 u p up up 点一定是 x x x 的祖先。不妨这里设 u p 1 up1 up1 u p 2 up2 up2 的祖先。

容易发现, u p 1 up1 up1 x x x 的一整条路径都出现在了两个环中,所以这样是矛盾的,原结论得证。


T425915 仙人掌图最大独立集

首先默认已经做过基环树版本的 骑士 那道题了。

回顾一下那道题的做法,可以发现对于一条回边 u p → d n up \to dn updn 构成的环,我们是在原有的 没有上司的舞会那道题 d p dp dp 状态上进行了一个升维,在记录子树根结点有没有选的同时还记录了 d n dn dn 有没有选。

考虑将这种方法扩展到仙人掌图上面,但是我们发现一个结点的子树里面可能有很多的 d n dn dn(并不是只有一个环了),而且数量是会变化的,而我们又不可能 2 n 2^n 2n 记录所有的 d n dn dn 选没选,所以在状态设计方面遇到了一点“困难”。

但是我们发现,上述结论 3 就是为我们量身定制的,因为其他已经被考虑过的环已经不用再考虑(这是仙人掌图,不会出现环套环的情况),所以只需要把目光放在这个没有走到 u p up up d n dn dn 点就行了。

所以就可以设计状态了。至此思路已经成型,直接把那道题的代码拿过来改改就行了。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 50010;
int n;
vector<int> v[N];
int dp[N][4];
bool stk[N], vis[N];
int up[N];
int m;void dfs(int u, int pre) {vis[u] = stk[u] = 1;dp[u][1] = dp[u][3] = 1, dp[u][0] = dp[u][2] = 0;for (auto i : v[u])if (!vis[i]) {dfs(i, u);if (up[i] != 0 && up[i] != u)up[u] = up[i];if (u == up[i]) {dp[u][0] += max(max(dp[i][0], dp[i][1]), max(dp[i][2], dp[i][3]));dp[u][1] += dp[i][0];dp[u][2] += max(max(dp[i][0], dp[i][1]), max(dp[i][2], dp[i][3]));//很容易发现,对于一个环结束的时候,可以取 dp[2] 和 dp[0] 的增量相同,dp[3] 和 dp[1] 的增量相同dp[u][3] += dp[i][0];} else {dp[u][0] += max(dp[i][0], dp[i][1]);dp[u][1] += dp[i][0];dp[u][2] += max(dp[i][2], dp[i][3]);dp[u][3] += dp[i][2];}} else if (i != pre && stk[i])up[u] = i, dp[u][1] = dp[u][2] = -1e16;stk[u] = 0;
}signed main() {cin >> n >> m;for (int i = 1; i <= m; i++) {int x, y;cin >> x >> y;v[x].push_back(y), v[y].push_back(x);}dfs(1, 0);cout << max(dp[1][0], dp[1][1]) << endl;return 0;
}

可以发现,这份代码和骑士那道题的那份代码是差不多了,主要改动就是把原来的单个元素 u p up up 变成了一个数组 up[]

最大独立集时间复杂度

学了这么多独立集,来总结一下各种图的求最大独立集的时间复杂度。

首先对于一般图,求独立集属于 NP 完全问题,也就是只能暴力枚举。

对于二分图,设点数 n n n,边数 m m m,则可以使用网络流将复杂度变成 O ( m n ) O(m \sqrt n) O(mn ) 的级别(网络流还没学过qwq)。

对于仙人掌图,也包含了树和基环树,可以使用深搜树 + dp 的方式把复杂度变成 O ( n + m ) O(n+m) O(n+m) 的级别。

对仙人掌图进行缩点

发现仙人掌是一堆环通过一堆边拼在一起,两两之间彼此不相交。显然会发现,这个时候若把每一个环都看作是一个点,那么最终就会变成一棵树,在上面可以跑各种各样的科技。

那么怎么看作是一个点呢???通过 P5236 的圆方树做法,我们想到了可以配合点双连通分量进行缩点。

考虑仙人掌图中的每一个点双,不难发现是这样子的:

  • 每一个点双恰好是一个简单环,或者是恰为一条非环边。

显然简单环一定是极大的点双连通分量,但是剩下的边中的每一条边也会变成一个点双连通分量,所以上面的那句话是正确的。

例如这个仙人掌图的深搜树,树边用实线,回边用虚线:

所有的点双连通分量现在已经用彩色线圈出来了,在旁边写上了新的编号。

最终得到的园方树如下:

以前我们就知道圆方树有着求必经点和可经点的作用,但是在对仙人掌图缩点的时候它会有更大的作用。

观察绿色点双连通分量,发现其 u p up up 结点为 3 3 3 号结点(这里 u p up up 结点为点双连通分量最高的结点,而 d n dn dn 结点为点双连通分量最低的结点),而对应到圆方树里面,发现 3 3 3 就是其父亲!

整理一下可得:

新性质:圆方树里方点的父亲恰好是深搜树中其对应的点双里最高的点。


考虑另一件事情:如何处理环上两点之间的最短距离。

不妨在圆方树里面,针对 14 14 14 号方点进行举例,即原深搜树中的绿色点双连通分量的部分。后面的抽象文字如果有不懂的可以对照着图片想想为什么。

因为获取距离的方法较为套路,这里就简要讲讲思考在这个方法的过程。

发现一个环一定是一条链加上一条回边,这是不由分说地。而且还可以发现两点之间的距离要么是在这条构成环的链上的距离(也就是直接从深度小的点通过走链走到深度大的点),要么是从另一个方向过来的距离(也就是先从深度小的点走到 u p up up,然后再走 d n dn dn,再有 d n dn dn 走到深度较大的点)

显然两点之间的最短距离就是上面两片粗体字得到答案的 min ⁡ \min min 值。但是这两个答案太难算了,有没有一些突破口呢?

显然是有的,因为我们可以发现第一托路径的答案 + + + 第二托路径的答案 = = = 整个环的路径权值和。

那么就可以通过路径权值和来快速通过前者得到后者。而且路径权值和是一个定值,因为其他地方没地方放了,就直接把环里面的路径权值和作为这个环对应的方点的点权即可。

而对于前面提到的第一托可能的路径,可以使用在链上 u p up up 到这个点的距离来记录。这样就做完了。最终还有每一个方点到其 u p up up 的距离设为 0 0 0

总结一下:

  • 方点到其 u p up up 的边权设为 0 0 0

  • 圆点到方点的边权,设为在深搜树中方点的 u p up up 到圆点的链上距离。

  • 将方点的点权设为环内所有边权的总和。

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

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

相关文章

华为OD机试真题——洞穴探险(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

Java设计模式之职责链模式详解

Java设计模式之职责链模式详解 一、职责链模式核心思想 核心目标&#xff1a;将请求的发送者与接收者解耦&#xff0c;使多个对象都有机会处理请求。这些处理者形成链式结构&#xff0c;请求沿链传递直到被处理或到达链尾&#xff0c;如政府审批层层上报机制。 二、职责链模式…

解决WPF短暂的白色闪烁(白色闪屏)

在 WPF 应用程序启动时出现 短暂的白色闪烁&#xff08;白色闪屏&#xff09;&#xff0c;通常是由于以下原因导致的&#xff1a; 主要原因 WPF 默认窗口背景是白色&#xff0c;在加载 UI 之前会短暂显示白色背景。 解决方案 设置窗口背景为透明或黑色&#xff08;推荐&…

《Python基础》第1期:人生苦短,我用Python

介绍 Python 在英语中是蟒蛇的意思&#xff0c;它的 logo 也是两条蟒蛇缠绕在一起。 然而 Python 和蟒蛇实际上没有半点关系。 Python 是由荷兰程序员 Guido van Rossum&#xff08;因为其名字的前三个字母“gui”是中文“龟”的拼音&#xff0c;所以江湖人称“龟叔”&#x…

DiT、 U-Net 与自回归模型的优势

DiT 相对于 U-Net 的优势 全局自注意力 vs. 局部卷积 U-Net 依赖卷积和池化/上采样来逐层扩大感受野&#xff0c;捕捉全局信息需要堆叠很多层或借助跳跃连接&#xff08;skip connections&#xff09;。DiT 在每个分辨率阶段都用 Transformer 模块&#xff08;多头自注意力 ML…

怎么查找idea插件的下载位置,并更改

长期使用 IntelliJ IDEA 时&#xff0c;默认存储在 C 盘的配置文件会持续生成大量缓存和日志文件&#xff0c;可能导致系统盘空间不足。通过修改默认配置文件存储位置&#xff0c;可以有效释放 C 盘空间并提升系统性能。 1&#xff0c;先找到自己idea的下载目录&#xff0c;再打…

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)

文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子&#xff08;远程代理&#xff09; 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息&#xff08;数据上报消息&#xf…

15.进程间通信(一)

一、进程间通信介绍 进程间通信目的&#xff1a; 数据传输&#xff1a;一个进程需要将它的数据发送给另⼀个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xf…

05-jenkins学习之旅-vue前项目部署实践

1、创建被管理项目 2、构建流程说明 jenkins其实就是将服务部署拆分成了&#xff1a; 1、拉取代码(git) 2、打包编译(npm install) 3、自定义脚本(dist复制、执行启动脚本) 4、部署成功后的一些通知等 3、demo配置 3.1、General 3.2 源码管理 添加用户名密码方式如下图 3.2…

服务器中分布式存储数据技术都包含哪些内容?

随着大数据时代的到来&#xff0c;企业和组织对于服务器的存储要求也在不断地增高&#xff0c;传统的存储架构已经无法满足一些大规模的数据存储和处理需求&#xff0c;分布式存储技术应运而生&#xff0c;成为了大数据存储的重要基础设施&#xff0c;下面&#xff0c;就来介绍…

从比分滚动到数据革命:体育数据如何重构我们的观赛体验?

当凌晨三点的欧冠决赛与闹钟冲突时&#xff0c;当世界杯小组赛因时差难以全程跟进时&#xff0c;当代体育迷早已不再依赖电视直播 —— 打开手机里的比分网&#xff0c;实时跳动的体育大数据正构建着全新的观赛宇宙。这些曾经被视为 "辅助工具" 的平台&#xff0c;如…

vue2使用element中多选组件el-checkbox-group,数据与UI更新不同步

问题描述 使用element多选checkbox组件&#xff0c;点击勾选取消勾选&#xff0c;视图未变化&#xff0c;再次点击表单其他元素&#xff0c;多选组件勾选状态发生变化&#xff0c;视图和数据未同步 第一次尝试&#xff1a;再el-checkbox-group多选父组件上增加点击事件&…

CodeTop之LRU缓存

题目链接 146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09; 题目解析 算法原理 我们使用双向链表哈希表的形式来模拟缓存机制 首先我们要自己实现一个双链表, 自己写一个内部类, 这个内部类记录了key,value,prev,next(前驱和后继), 后续我们就通过这个内部类来构造双…

PyQt学习系列11-综合项目:多语言文件管理器

PyQt学习系列笔记&#xff08;Python Qt框架&#xff09; 第十一课&#xff1a;综合项目 - 多语言文件管理器 &#xff08;原课程规划中的第十五课&#xff0c;按用户要求调整为第十一课&#xff09; 课程目标 综合运用PyQt框架开发一个支持多语言的文件管理器实现以下核心功…

【Ubuntu修改串口延时(Latency Timer)为1毫秒(设备拔插或系统重启后自动生效)】

Ubuntu修改串口延时Latency Timer为1毫秒-设备拔插或系统重启后自动生效 在Ubuntu系统中&#xff0c;串口设备的延时参数(latency_timer)可以通过udev规则永久修改。以下是完整步骤&#xff1a; 创建udev规则文件 sudo vim /etc/udev/rules.d/99-ftdi-low-latency.rules添加以…

OpenCV CUDA模块图像处理------颜色空间处理之GPU 上交换图像的通道顺序函数swapChannels()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于在 GPU 上交换图像的通道顺序&#xff08;例如将 BGR 图像转为 RGB&#xff09;。 它适用于多通道图像&#xff08;如 3 通道或 4 通道…

Linux Ubuntu24.04配置安装MySQL8.4.5高可用集群主从复制!

MySQL 主从复制&#xff08;Replication&#xff09;是实现数据高可用、读写分离及异地容灾的核心机制之一。主库写、从库读&#xff0c;提升并发能力&#xff1b;读写分离&#xff0c;减轻主库压力。 本地 windows 系统有一个Linux Ubuntu子系统&#xff0c;版本为Ubuntu 24.…

R基于逻辑回归模型实现心脏病检测及SHAP值解释项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后关注获取。 1.项目背景 心血管疾病是全球范围内导致死亡的主要原因之一&#xff0c;每年有数百万人因此失去生命。在众多的…

嵌入式学习笔记 -函数嵌套时以及异常响应时,LR使用的具体过程

函数嵌套时以及异常响应时&#xff0c;寄存器LR的作用存在显著区别&#xff0c;理解这个问题对于理解freeRTOS底层代码的实现大有帮助&#xff0c;具体使用过程如下&#xff1a; 一 函数嵌套时的LR使用的具体过程 在ARM架构(特别是M0处理器)中&#xff0c;函数嵌套调用时LR(L…

Java String函数的使用

文章目录 String字符串比较字符串查找转化字符串替换字符串拆分字符串截取&#xff08;常用&#xff09;字符串的不可变性 String str本来是字符串常量的引用&#xff0c;应该打印地址&#xff0c;但是编译器重写了toString方法&#xff0c;所以打印hello String 的构造方法 …