luogu P3387 【模板】缩点

原题链接

原题再现

题目描述

给定一个 n 个点 m 条边有向图每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入格式

第一行两个正整数 n,m。

第二行 n 个整数,其中第 i 个数 ai​ 表示点 i 的点权。

第三至 m+2 行,每行两个整数 u,v,表示一条 u→v 的有向边。

输出格式

共一行,最大的点权之和。

题意简述

有向图,点都有点权。点可以经过多次,但点权只能加一次。

求这张图的最大权值。

解题思路

如果一个强连通分量上的某个点被选中,那么选择整个强连通分量显然更优。因为这样可以最大化点权总和。这样一来,可以把整个强连通分量视为权值为强连通分量中所有点权值之和的整体点,选择这个强连通分量上任意一点就意味着选择整个强连通分量。所以缩点。

缩点,也就是将强连通分量合并为单点,将原来k个强连通分量的图简化成只有k个点的有向无环图(DAG)。Tarjan算法实现。

Tarjan算法

在DFS搜索遍历整个图的过程中,把有向图划分为DFS搜索树及非树边。

与传统的DFS不同的是,多了回溯这一步。

非树边可以被分为:

  1. 返祖边(回边):从树上的后代指向祖先,如7→1。
  2. 横叉边:无直接祖先关系且分属不同子树,如9→7。
  3. 前向边:从树上的祖先指向后代,如3→6。

在遇到非树边时,有相应的操作。

如果结点 u 是某个强连通分量在DFS搜索树中遇到的第一个结点,那么这个强连通分量的其余结点肯定是在DFS搜索树中以 u 为根的子树中。结点 u 被称为这个强连通分量的根。

关键数据结构

  • 数组dfn:dfn[i]表示第一次发现i的时间戳,亦可判断是否为被访问。
  • 数组low:low[i]表示i的追溯值,u或u的子树能够追溯到的最早的栈中节点的次序号。
  • 数组vis:vis[i]表示i是否正在访问,即是否在栈中。
  • t:时间戳。
  • scc:强连通分量个数。
  • 栈st:栈保存了当前深度优先搜索(DFS)路径上的所有节点。这些节点可能属于同一个强连通分量,但尚未确认是否构成完整的SCC。用于追溯。
  • 数组color:每个节点标记其所属的强连通分量编号。
void tarjan(int v) {dfn[v] = low[v] = ++tot; //标记dfn[]访问顺序,还有low[]的初始值sta.push(v);             //让点v进栈vis[v] = true;           //标记这个点被访问过for (int i = head[v]; ~i; i = edge[i].next) { //一直循环这个点每一个出度,直到-1表示没有了,这也是为什么memset head数组时要赋-1int u = edge[i].to;               //定义u并把它赋成这条边的终点if (!dfn[u]) {                    //如果u没有被访问过tarjan(u);                      //找下面这个点low[v] = min(low[v], low[u]);   //这个点low[v]的值就是当前low[]的值与找到的u点的low[]值} else if (vis[u])                //如果u被访问过了,但是还在队列中low[v] = min(low[v], dfn[u]);   //low[v]就取这个点的low值与循环到的点u的dfn[u]的最小值}if (dfn[v] == low[v]) {   //如果发现v这个点的dfn[]和low[]相等,说明这个点是一个强连通分量的“根”。sccnt++;int u;                  //定义u变量,作为栈顶元素do { u = sta.top();        //将u赋值为sta栈的栈顶元素vis[u] = false;       //将u弹出sta.pop();            //同上color[u] = sccnt;     //将u标记为这个强连通分量里的点} while (v != u);       //当v == u之后,结束循环}
}

参考文献

强连通分量 - OI Wiki

速通Tarjan与强连通分量

全网最最详细!一文讲懂Tarjan算法求强连通分量&缩点 - 淼畔 - 博客园

tarjan算法详解--关于图的连通性 & 连通分量 - 知乎

tarjan算法总结 (强连通分量+缩点+割点),看这一篇就够了~_强连通分量切割-CSDN博客

浅谈 tarjan-腾讯云开发者社区-腾讯云

Tarjan-1972.pdf

深入浅出 Tarjan 算法 (一)

60 分钟搞定图论中的 Tarjan 算法(一) - 知乎

写在最后

说实话,我作为初学者,学这个算法的时候挺吃力,看了不少网上的算法书(原因就是把算法书全都忘在学校了QAQ),可能是鄙人智力有限的原因吧。所以我决定自己录一个视频,演示一下这个过程。

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

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

相关文章

P1119 灾后重建【题解】

P1119 灾后重建 题目背景 B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通…

Horse3D引擎研发笔记(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制

在Horse3D引擎的研发过程中,我们致力于构建一个高效、灵活且易于扩展的3D图形引擎。在本篇博客中,我们将详细记录如何基于QtOpenGL框架,使用仿Three.js的BufferAttribute结构,重构三角形绘制流程。通过这一过程,我们希…

MCU程序段的分类

程序的下载(烧录到存储器中)通常是按照程序文件分段(Code段、RO_data段、RW_data段、ZI_data段)的方式存储的,但运行时内存的布局会按照程序进程分段(TEXT段、DATA段、BSS段、堆栈段)进行组织。…

综合项目记录:自动化备份全网服务器数据平台

一、项目背景与需求1.1项目概述该项目共分为2个子项目,由环境搭建和实施备份两部分组成1.2项目总体需求企业内部有一台web服务器,内部数据很重要,现需要为该web服务器数据做备份,这样在数据丢失时可以恢复。要求如下:每…

联合索引全解析:一棵树,撑起查询的半边天

目录 一、为什么联合索引是MySQL性能优化的“王牌”? (一)索引的基本结构:从聚簇到非聚簇 1. 聚簇索引(Clustered Index) 2. 非聚簇索引(Secondary Index) (二&…

vue开发的计算机课程页面

课程信息展示页面设计与实现我将设计一个美观且实用的课程信息展示页面,重点展示计算机网络应用课程的相关信息。设计思路使用卡片式布局清晰展示课程各模块信息采用科技感配色方案,符合计算机网络课程主题添加动画效果增强用户体验响应式设计确保在各种…

MySQL 正则表达式详细说明

目录 MySQL 正则表达式详细说明 1. 基本操作符:REGEXP 和 RLIKE 2. 常用正则表达式模式 3. MySQL 正则表达式函数(MySQL 8.0) 4. 示例查询 5. 注意事项 6. 总结 MySQL 正则表达式详细说明 MySQL 支持正则表达式(Regular Ex…

c++之 栈浅析

C之栈浅析 概要 通过可视化游戏梳理栈特点以及栈操作方式. 学习栈的工作原理就像往糖果罐里放糖果和拿糖果一样简单! 栈特点 先进后出 技术名词解释 LIFO LIFO -> Last In, First Out 后进先出 可视化小游戏 游戏传送门

C++ 算术函子

在 C 中&#xff0c;算术函子&#xff08;Arithmetic Functors&#xff09; 是标准库 <functional> 中提供的一组函数对象&#xff0c;用于封装基本的算术运算&#xff08;如加、减、乘、除等&#xff09;。它们本质上是类模板&#xff0c;重载了 operator()&#xff0c;…

Flutter 事件总线 Event Bus

文章目录概要核心原理基本使用步骤优点注意事项适用场景小结概要 提示&#xff1a;这里可以添加技术概要 event_bus 是一个常用的第三方库&#xff0c;用于实现跨组件 / 跨页面的事件通信&#xff0c;基于发布 - 订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;工…

数据库管理系统:入门需要了解的内容

数据库管理系统&#xff1a;数字化时代的基石 在信息技术飞速发展的今天&#xff0c;我们生活在一个被数据包围的世界里。从日常使用的社交媒体、电商平台&#xff0c;到企业运营的核心业务系统&#xff0c;再到政府部门的政务管理&#xff0c;数据无处不在。而数据库管理系统&…

安装CST时,报错问题处理

今天安装这个软件的时候&#xff0c;发现一个问题一直处理不了&#xff0c;然后看网上的一些解决方法&#xff0c;最终得到处理&#xff0c;这里就简单记录下解决方法。问题&#xff1a;处理方案&#xff1a;1.问题原因&#xff1a;crack中的CST Studio Suite 2022未配置成功。…

分治-快排-215.数组中的第k个最大元素-力扣(LeetCode)

一、题目解析1、需返回排序好的第k个最大元素2、要求时间复杂度为O(N)二、算法原理解法1&#xff1a;堆排序(大根堆) k*O(N)借用大堆的性质&#xff0c;将元素插入到大堆中&#xff0c;按照k输出堆顶第k个元素解法2&#xff1a;堆排序(小根堆) (N-k)*O(logN)先建k个小堆&#x…

新手向:Python实现图片转ASCII艺术

Python实现图片转ASCII艺术&#xff1a;从零开始的完整指南Python实现图片转ASCII艺术的技术解析ASCII艺术是一种使用字符组合来表现图像的技术&#xff0c;这种技术源于早期计算机显示器的图形限制&#xff0c;如今已成为一种独特的数字艺术形式。ASCII艺术的应用场景十分广泛…

6.类与对象(二)

总结 本章写了封装、static成员以及代码块。 一、封装 1.封装的概念 封装简单来说就是被密封起来&#xff08;不让我们看见的东西&#xff09;&#xff0c;即被隐藏。 对于用户来说&#xff0c;并不需要关心的类&#xff0c;所实现的细节就会被封装&#xff08;隐藏&#x…

流形折叠与条件机制

1. 为什么要防止流形折叠&#xff08;mode collapse&#xff09; 流形折叠 生成器只学会输出极少数甚至单一模式&#xff08;mode&#xff09;的样本&#xff0c;而完全忽略数据分布的多样性。 后果一句话&#xff1a;“模型看起来生成了很多图&#xff0c;其实都在重复同一张…

《从零构建大语言模型》学习笔记2,文本数据处理1(以及tiktoken库无法下载gpt2参数,调用get_encoding时SSL超时的解决方法)

《从零构建大语言模型》学习笔记2&#xff0c;文本数据处理1 文章目录《从零构建大语言模型》学习笔记2&#xff0c;文本数据处理1前言1、分词2.将把提取出来的词元转换为数字ID3.添加特殊上下文标记4. 字节对编码&#xff08;以及tiktoken库无法下载gpt2参数&#xff0c;调用g…

【AI工具】解放双手,操控浏览器的工具对比,来了

&#x1f4d2;前言在github上面&#xff0c;有几个操作浏览器的mcp工具&#xff1a;browser-use / browser-usemicrosoft / playwright-mcpAgentDeskAI / browser-tools-mcphangwin / mcp-chrome想知道他们的区别吗&#xff0c;想知道那个更适合你吗&#xff0c;想。。。&#…

Linux 操作系统基础知识总结

1、操作系统总体介绍 CPU&#xff1a; 就像人的大脑&#xff0c;主要负责相关事情的判断以及实际处理的机制。 查询指令&#xff1a; cat /proc/cpuinfo 内存&#xff1a; 大脑中的记忆区块&#xff0c;将皮肤、眼睛等所收集到的信息记录起来的地方&#xff0c;以供CPU进行判断…

cudagraph 本质详解

理解 CUDA Graph 的本质,关键在于理解它解决了什么问题,以及它通过什么机制来解决这个问题。 一、 核心问题:传统 CUDA 编程的“CPU 瓶颈” 在 CUDA Graph 出现之前,我们通常使用 CUDA Stream 来向 GPU 提交任务。这是一个动态的过程: CPU 作为指挥官:CPU 循环地、逐条…