Tarjan 之 SCC 与 缩点

news/2024/9/19 15:41:36/文章来源:https://www.cnblogs.com/sea-and-sky/p/18368153

这篇文章将讲述作者对 Tarjan求SCC与缩点(不是割点)的理解

让我们开始吧!

Tarjan SCC 与 缩点

既然要求 \(SCC\) 那我们先要弄明白 什么是 SCC

SCC 指的是强连通分量

强连通指的是若一张有向图的节点两两互相可达,则这张图是强连通的

强连通分量 指的是一个极大连通子图
此处的极大指的是一个子图再多一个节点都将不强连通

那么知道了这个,我们就可以继续了

tarjan求SCC的算法和之前求 LCA 的Tarjan 有些类似之处

这是tarjan求SCC所需的数组

  • \(dfn[x]\) 表示 \(x\) 节点的DFN序即遍历顺序
  • \(low[x]\) 表示 \(x\) 节点所能到达的 DFN序最小 的节点 PS:可以经过多条边
  • \(stk[]\) 求SCC所需的栈
  • \(instk[x]\) 表示 \(x\) 节点是否在栈中
  • \(scc[x]\) 表示 \(x\) 节点在编号为几的 SCC之中
  • \(siz[k]\) 表示 编号为 \(k\) 的一个SCC的大小

其中 \(dfn\) , \(low\) , \(instk\)\(scc\) 都是可以放在一个结构体中的

数组有点多,不要慌, 我们一点点来讲讲算法的流程

首先,对于一个图,我们在深搜遍历时,每个点只会进入一次,而这将产生一个搜索树

例如对这个图
image

我们会产生一颗如下的搜索树
image

当我们在深搜进入点 \(x\) 时, 标记其 的深搜序 然后把它放入栈中

然后遍历他的所有边能到的点 \(y\)

y 有且仅有 3 种情况

  1. y没被遍历过且不在栈中 对于这种情况,我们继续递归 \(y\) 然后 用 \(low[y]\) 来更新 \(low[x]\) 就是将 \(low[x]\) 变成 \(low[x]\)\(low[y]\) 最小的那个

  2. y被遍历过且在栈中,对于这种情况我们用 \(low[y]\) 来更新 \(low[x]\)

  3. y被遍历过且在栈中,说明这个点我们已经处理完了,就不用管了

在遍历完后,我们检查 \(dfn[x]\) 是否等于 \(low[x]\)
若相等,则说明 \(x\) 是一个 SCC 的根

先证明为什么,然后再继续讲

\(low[x]\) 的定义可得,\(x\) 所能到达的 \(dfn\) 编号最小的节点就是 他自己

就像这个图

image

由于 \(x\) 能够走到他自己,那么 \(x\) 一定在一个环中,再感性理解一下(我还不知道怎么证明这是极大的 QwQ upt:证明见下面),\(x\) 一定是一个 SCC 的根

所以,我们不断弹栈知道将 \(x\) 弹出去,将弹出去的每个节点标记所在的 SCC 编号,然后取消入栈标记, 将 \(siz[编号]++\)

这是因为以 \(x\) 为根的 SCC 一定都在 \(x\) 之后入栈 ,而所有的不在 以 \(x\) 为根的 SCC 中 的 节点 一定 在回溯到 \(x\) 之前已经被相同的流程处理掉了,已经出栈了,栈中还在 \(x\) 之后的一定都属于以 \(x\) 为根的 SCC

以一个图为例子
image

还有没讲详细的后面再补吧,结合代码感性理解一下

上代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node
{vector<int> to;//能到达的点int dfn;int low;//能访问到的dfn最小的节点bool instk;bool vis;
};
node nodes[1000000];
int tot;//dfn
int stk[100000],scc[100000],siz[100000]/*SCC大小*/,cnt/*SCC编号*/,top/*栈顶*/;void tarjan(int x)
{nodes[x].dfn=++tot;//记录DFNnodes[x].low=tot;stk[++top]=x;nodes[x].instk=1;int to_;for(int y=0; y<nodes[x].to.size(); y++){to_=nodes[x].to[y];if(nodes[to_].dfn==0)//若没访问过 {tarjan(to_);//深搜nodes[x].low=min(nodes[x].low,nodes[to_].low);//更新}else if(nodes[to_].instk)//若y已访问且在栈中 {nodes[x].low=min(nodes[x].low,nodes[to_].dfn);//更新}}if(nodes[x].dfn==nodes[x].low)//若这个节点能链接到自己说明是一个SCC的根 {int y;cnt++;do//将节点出栈{y=stk[top--];nodes[y].instk=0;scc[y]=cnt;++siz[cnt];}while(y!=x);}}
int main()
{ios::sync_with_stdio(0);cin>>n>>m;int a,b;for(int ww=1;ww<=m;ww++){cin>>a>>b;nodes[a].to.push_back(b);}for(int i=1;i<=n;i++){if(!nodes[i].dfn)//图可能不联通{tarjan(i);}}cout<<cnt;return 0;}

啊对了,还有缩点

简单来说就是把一个 SCC 看做一个点来处理,啊应该就是这样,没了


完结·散花!

没想到这样一篇文章要写整整一个小时啊啊啊

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

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

相关文章

马哥教育 c10网络安全 第二周作业 2024/8/17

1、使用 html 写一个网页,要求满足以下条件: (1)网页中含有任意一张图片,图片路径使用绝对路径,鼠标悬停在图片时出现“马哥教育”文本,且点击图片可跳转至马哥教育官方页面 (2)网页中包含账号、密码登录,且账号提前定义好是 admin 且不可更改,输入密码时显示加密形…

FinalShell工具的使用

第1篇 FinalShell工具的使用1.介绍 xshell作为Linux远程连接的工具,教程请看《通过xshell远程连接ubuntu》。但是,xshell是付费软件。于是,找到一个finalshell作为其替换软件。 FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分…

c10 第二次作业 2024/8/17

1、使用 html 写一个网页,要求满足以下条件: (1)网页中含有任意一张图片,图片路径使用绝对路径,鼠标悬停在图片时出现“马哥教育”文本,且点击图片可跳转至马哥教育官方页面 (2)网页中包含账号、密码登录,且账号提前定义好是 admin 且不可更改,输入密码时显示加密形…

博客模版

第1篇 FinalShell工具的使用1.介绍 xshell作为Linux远程连接的工具,教程请看《通过xshell远程连接ubuntu》。但是,xshell是付费软件。于是,找到一个finalshell作为其替换软件。 FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分…

打印99乘法表

我们的核心思想是以小化大 1.先写出1的所有乘法2.设置一个变量,使得不止有1乘n3.将1的乘法放入变量中,使得1再次被循环包起来4.解决重复乘法图片中出现了两次1*4,说明刚才的表达式会有重复相乘 出现重复的原因: a有1~9的数字 而i也会有1~9, a*i就必然会有重复,我们需要让…

动态dp

T1 一共 \(n\) 颗糖果,第 \(i\) 颗的价值为 \(a[i]\),你不能连着选两颗,请问你的选到的最大价值为多少 显然有如下写法 : 设 \(dp[i][0/1]\)表示选到了第 \(i\) 颗,第 \(i\) 颗选或不选 显然有转移 : \(dp[i][0] = max(dp[i - 1][0], dp[i - 1][1])\) \(dp[i][1] = max(dp[i - …

Linux学习/TCP Socket通信

Linux下的TCP Socket通信案例及详解案例 案例一 server.c #include <stdio.h> // 标准输入输出 #include <stdlib.h> //提供通用的工具函数,例如内存分配和程序退出。 #include <string.h> //提供字符串处理函数。 #include <unistd.h> //提供对 POSI…

Rockylinux 9.4 安装部署

Rockylinux安装部署 1、操作系统引入 2024 年 6 月 30 日,CentOS Linux 7 终止其生命周期(EOL),至此 CentOS 全系列版本也已停止维护,属于 CentOS 的时代彻底终结。CentOS 停止维护后,用户将无法获得包括问题修复和功能更新在内的任何软件维护和支持,宕机、服务中断、数…

Rockylinux安装部署

Rockylinux安装部署 1、操作系统引入 2024 年 6 月 30 日,CentOS Linux 7 终止其生命周期(EOL),至此 CentOS 全系列版本也已停止维护,属于 CentOS 的时代彻底终结。CentOS 停止维护后,用户将无法获得包括问题修复和功能更新在内的任何软件维护和支持,宕机、服务中断、数…

NSSCTF [SWPUCTF 2021 新生赛]pop

NSSCTF [SWPUCTF 2021 新生赛]pop进入就看见一串代码,直接开启代审<?phperror_reporting(0); show_source("index.php");class w44m{private $admin = aaa; protected $passwd = 123456;public function Getflag(){//通过该函数来获得flagif($this->admin ==…

性能测试之中间件:告诉你什么是 kafka 和 MQ ?

在如今这个数据驱动的时代,中间件在性能测试中扮演着至关重要的角色。你是否曾听说过Kafka和MQ,却不清楚它们在实际应用中具体的作用是什么?让我们一起来揭开它们的神秘面纱。 Kafka和MQ究竟是什么?它们在性能测试中如何发挥作用,又为何成为现代分布式系统中的关键组成部分…

tcp与udp的总结+connect阻塞+tcp三次握手、四次挥手+常见的服务器IO(发送数据+接收数据)模型

一,TCP与UDP的基本总结 TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议。TCP是面向连接的,提供可靠、顺序的传输,适用于需要高可靠性的应用,如网页浏览和文件传输。它通过重传机制和流量控制确保数据完整性。UDP是无连接的,速度快但不保证数据的可靠性…