分层图

news/2024/12/22 0:32:49/文章来源:https://www.cnblogs.com/yiming564/p/18447666

分层图

前言

在一次模拟赛中,我遇到了 [USACO15JAN] Grass Cownoisseur G 这道题,当时不知如何下手,和边上的同学偷偷讨论,听别人说是分层图,建两份图然后连一层反向边即可,当时对这个图论建模大为惊叹(不亚于我在学网络流时学到拆点拆边),故专门写一篇博客记录之。

算法思想

分层图是图论建模的一个巧妙的工具,主要用来解决类似以下形式的问题:

在图中求最短路,但可以做不多于 \(k\) 次的特殊转移,求最短路。
一般题目中的 \(k\) 不会较大

对于这种题目,可以使用分层图解决。

方法是建立 \(k + 1\) 层架构与原图相同的图,然后将特殊转移用有向边的形式连接第 \(i\) 层和第 \(i + 1\) 层节点,则可以使用图论建模来描述原图的 \(k\) 次决策。

例题

[USACO15JAN] Grass Cownoisseur G

题意:给定一个 \(n\)\(m\) 边的有向图,节点编号 \(1 \dots n\)
定义一条路径的长度为该路径上经过的所有不同的节点的总数,求 \(1\)\(1\) 的最长路。
特殊转移:可以在任意时刻走最多一次反向边。

这道题是我在考场上遇到的题目,当时并未场切,丢人丢大了。

首先,建两份与原图相同的图,对于原图节点 \(i\),其在第二层图的对应节点为 \(i + n\),用反向边连接两层图。

for (int i = 0; i < m; i++)
{read(u), read(v);add_edge(v, u + n);	// 跨层级反向边add_edge(u, v), add_edge(u + n, v + n);	// 建两份图
}

考虑到原题要求最长路,而原图全都是正权环,因此要先 \(\text{Tarjan}\) 缩点再求最短路。

同时,注意到 \(\text{Tarjan}\) 缩点具有性质:\(\text{SCC}\) 编号恰为逆拓扑序,则可以考虑直接逆拓扑序 \(\text{DP}\),显然有转移:

\[d_v = \max_{(u, v) \in E} d_u + w_v \]

其中 \(E\) 为边集,\(d_u\) 为缩点 \(u\) 到缩点 \(1\) 的距离,\(w_u\) 为缩点 \(u\) 包含的节点数量。

for (int u = id[1]; u; u--)for (auto &&v : DAG[u])chkmax(dis[v], dis[u] + cnt[v]);

则答案为 \(d_{1 + n}\)

有的题解会说答案为 \(\max{d_1, d_{1 + n}}\),其实不然。
\(\text{DP}\) 的形式计算贡献默认了 \(d_1\)\(0\),统计 \(d_1\) 无意义。
而且经过反向边的最长路一定不会比不经过反向边要劣,因为可以经过反向边后立即经过正向边。
因此直接统计 \(d_{1 + n}\) 即可。

总代码:

#include <bits/extc++.h>#define inline __always_inline
template <typename T> inline void chkmin(T &x, const T &y) { if (x > y) x = y; }
template <typename T> inline void chkmax(T &x, const T &y) { if (x < y) x = y; }
template <typename T> inline void read(T &x)
{char ch;for (ch = getchar(); !isdigit(ch); ch = getchar());for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
}
const int MaxN = 2e5 + 5;int n, m, u, v;
std::vector<int> graph[MaxN], DAG[MaxN];
inline void add_edge(int u, int v) { graph[u].push_back(v); }
char visit[MaxN];
int dis[MaxN], cnt[MaxN], id[MaxN], low[MaxN], dfn[MaxN], cur = 1, scc = 1;
int queue[MaxN], *head = queue, *tail = queue;
void tarjan(int u)
{low[u] = dfn[u] = cur++;visit[*tail++ = u] = 1;for (auto &&v : graph[u])if (!visit[v])tarjan(v), chkmin(low[u], low[v]);else if (visit[v] == 1)chkmin(low[u], dfn[v]);if (low[u] == dfn[u]){while (*tail != u)cnt[id[*--tail] = scc]++, visit[*tail] = 2;scc++;}
}int main()
{read(n), read(m);for (int i = 0; i < m; i++)read(u), read(v), add_edge(v, u + n), add_edge(u, v), add_edge(u + n, v + n);n <<= 1;for (int u = 1; u <= n; u++)if (!dfn[u]) tarjan(u);for (int u = 1; u <= n; u++)for (auto &&v : graph[u])if (id[u] != id[v])DAG[id[u]].push_back(id[v]);for (int u = id[1]; u; u--)for (auto &&v : DAG[u])chkmax(dis[v], dis[u] + cnt[v]);printf("%d", dis[id[1 + (n >> 1)]]);return 0;
}

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

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

相关文章

Linux系统安装Pycharm专业版【附破解方法】

​写在前面 本教程适用于 Pycharm 2022.2.3 以下所有版本 一、版本信息 虚拟机产品:VMware Workstation 17 Pro 虚拟机版本:17.0.0 build-20800274 ISO映像文件:ubuntukylin-22.04-pro-amd64.iso Pycharm版本:PyCharm 2022.3.3 (Professional Edition) 资源链接:https:/…

谷歌收录批量查询,谷歌收录批量查询的方法步骤

谷歌收录批量查询是网站管理员和SEO专家常用的一种方法,用于同时查询多个页面或网站在谷歌搜索引擎中的收录情况。以下是几种常见的谷歌收录批量查询方法及其步骤: 一、使用Google Search Console(谷歌搜索控制台) 虽然Google Search Console主要面向单个网站的监控和管理,…

怎么查看网站是否被谷歌收录,查看网站是否被谷歌收录的快速检测方法

查看网站是否被谷歌收录,有多种快速检测方法可供选择。以下是一些常用的方法: 一、使用“site:”指令 打开谷歌搜索引擎:在浏览器中打开Google.com,确保使用的是谷歌的官方搜索引擎。 输入查询指令:在搜索框中输入“site:”加上你的网站域名(注意使用英文状态下的冒号,并…

10 月 4 日 S 组 风 雨 大 作

智障行为+2T1 T2 T3 T40 0 0 0好吧至少下一次不会考更低了 T1 你有个 n 个点 m 条边的无向图,每条边都有红蓝两种颜色中的一种,保证红色的边形成了这个图的一个生成树。 你希望给这些边赋上边权,保证边权是 1 ∼ m 的排列,使得红色的边是最小生成树。 希望这些边权形成的序…

南沙C++信奥赛陈老师解一本通题: 1828:【02NOIP提高组】均分纸牌

​【题目描述】有n堆纸牌,编号分别为 1,2,…,n。每堆上有若干张,但纸牌总数必为nn的倍数。可以在任一堆上取若干张纸牌,然后移动。 移牌规则为:在编号为1的堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 n 的堆上取的纸牌,只能移到编号为n−1的堆上;其他堆上取的纸…

反射容斥

好久没写了呃呃呃……反射容斥恋のうた あとどれくらいの距離を 月へ歩いたら あとどれくらいの 寒い夜を重ねたら あとどれくらいの さよならを流したら まぶたの奥の泉が枯れ果てるとか 千年後もきっと続くだろう そう思ってた空洞を 満たしてあふれてしまうほどの この気持ち…

快乐数学5虚数

5 虚数 虚数总是让我感到困惑:这是一个数学抽象概念,方程是可处理它。 大学才会用到它。我们将用我们最喜欢的工具来攻克这个课题:关注关系,而非机械公式。 将复数视为数字系统的升级,就像零、小数和负数一样。 使用直观的图表,而不仅仅是文字,来理解概念。5.1 真正理解负…

Cisco Secure Firewall 3100 Series FTD Software 7.6.0 ASA Software 9.22.1

Cisco Secure Firewall 3100 Series FTD Software 7.6.0 & ASA Software 9.22.1Cisco Secure Firewall 3100 Series FTD Software 7.6.0 & ASA Software 9.22.1 Firepower Threat Defense (FTD) Software - 思科防火墙系统软件 请访问原文链接:https://sysin.org/blog…

冲刺 CSP 联训模拟 2

T1 挤压 概率期望,二进制拆位 看到异或想到拆位算贡献 \[\begin{aligned} ans&=\sum_xx^2P(x)\\ &=\sum_x(b_1+b_2+...+b_{30})^2P(x)\ \ \ (b_i表示\ x\ 二进制下\ i\ 位的值)\\ &=\sum_x(b_1b_1+b_1b_2+. . .b_{30}b_{29}+b_{30}b_{30})P(x)\\ &=\sum_i^{30…

智慧园区管理原型

智慧园区管理系统的构建是一个复杂而系统的工程,它融合了信息化、AI、物联网等多种先进技术,旨在提升园区的管理效率、服务质量以及企业运营效率。 一、明确系统目标和需求 需求收集与分析:首先,需要对园区的实际需求进行全面分析,包括园区类型(如产业园区、办公园区、住…

读数据湖仓07描述性数据

读数据湖仓07描述性数据1. 描述性数据 1.1. 基础数据中包含不同类型的数据,而不同类型数据的描述性数据也存在显著的差异 1.2. 尽管这些描述性数据存在根本性的差异,但通过描述性数据,我们可以全面了解基础数据中的数据 1.3. 通过分析基础设施中提供的描述性数据可以获得更详…

探索JVM的堆内存分布:官方图片展示

序章 截取Java官方的 堆内存分布相关图片 到本文。Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide Java 21 https://docs.oracle.com/en/java/javase/21/gctuning/preface.html下载为 pdf,搜索 Figure,截取其中的 堆内存分布相关…