(写的有点小多,慢慢看,会有收获的)
(1)
首先我们得了解,什么是强连通?
如果在一个有向图顶点子集内,任取两个点 u 和 v ,都能找到一条路径从 u 到 v ,则称该子集为强连通

(2)
其次我们得了解,什么是强连通分量?
如果我们在一个强连通的顶点集合内,加入其他其他任意顶点集合后,它都会变得不再是强连通的,则称该顶点集合为强连通分量

(3)
最后我们得了解,什么是强连通分量分解?
任意有向图都可被分解成若干个不相交的强连通分量(这个不相交,指不同分量中顶点都是不同的),这就是强连通分量分解

注意:我们一般是对有向有环图进行强连通分量,因为有向无环图中,没有强连通分量,无向图中,所有顶点集是一个强连通分量,这种分解没有意义

(4)
那我们怎么进行强连通分量分解?

我们首先进行一次 dfs ,选取任意顶点作为起点,遍历所有尚未访问过的顶点,并在回溯前给顶点标号(后序遍历),对剩余未访问过的顶点,不断重复上述过程
这次的标号主要是为了使越接近图的尾部,顶点的标号越小,为后续操作做铺垫

怎么标号?
我们可以建立一个 vector 容器,这样我们将越接近图的尾部的,越先放入

为什么可以从任何顶点开始?
因为我们是把尾部最先放入。不管我们从哪个点开始遍历,都能遍历到当前剩余顶点集当中,最接近尾部的点,所以不管我们从哪里遍历,都能将该点及该点后面的所有点正确放入。
例如我们按 1 2 3 号顶点的顺序开始遍历,那么我们放入的点,就是圈起来的部分。
很容易看出不管从哪个点开始,都能正确完成操作

为什么需要后序遍历?(即先向下递归,回溯时在放入 vector)
因为我们是越接近图的尾部,越先放入。
如果是前序遍历就相当于越接近头部越先放入,这样会出错,因为我们从任意顶点开始遍历,比如我们按 1 2 3 的顺序进行遍历,这样我们先放的相当于是 顶点1 ,而顶点 1 并非头部,这样就会出错

我们再进行一次 dfs ,先将所有边反向,然后以标号最大的顶点为起点进行 dfs ,每次 dfs 所遍历的顶点集合就构成了一个强连通分量,拿个数组保存以下各个点属于哪个强连通分量即可

反向,其实就是记录边的时候多记录一条反向边
从标号最大的开始遍历,其实就是将 vector 从后向前遍历一次

这个的思路是这样的:
因为我们是按从头部到尾部遍历,所以我们正在遍历的只有两种情况
例:如果我们遍历到 顶点1 ,此时没有遍历过的可能是 ”旁边“ 的,或者 “后面” 的
(阴影的相当于已经遍历过)
对于“旁边”:由于上游的点已经遍历过,所以旁边的点递归不到,所以不用考虑
对于“后面”:假设 顶点v 在 顶点u 的“后面”,因为在“后面”,所以有条 u 到 v 的路径,如果把边反向后,仍然 顶点u 有路径到达 顶点v ,相当于在正向图中有一条 v 到 u 的路径,证明 u 到 v 连通

代码如下:

#include <iostream>
#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
vector<int> data[10005];
vector<int> rdata[10005];
vector<int> flag;
int used[10005];
int kind[10005];
void add_edge(int i, int j)
{data[i].push_back(j);rdata[j].push_back(i);
}
void dfs(int v)
{used[v] = true;for(int i = 0; i < data[v].size(); i++){if(!used[data[v][i]]){dfs(data[v][i]);}}flag.push_back(v);
}
void rdfs(int v, int k)
{used[v] = true;kind[v] = k;for(int i = 0; i < rdata[v].size(); i++){if(!used[rdata[v][i]]){rdfs(rdata[v][i], k);}}
}
int scc()
{memset(used, false, sizeof(used));for(int i = 0; i < N; i++){if(!used[i]) dfs(i);}memset(used, false, sizeof(used));int num = 0;for(int i = flag.size() - 1; i >= 0; i--){if(!used[flag[i]]){rdfs(flag[i], num);num++;}}return num
}

强连通分量分解详解 超级详细相关推荐

  1. Redis五种数据类型应用场景详解(超级详细版)

    目录 NoSQL:一类新出现的数据库(not only sql) 特征 NoSQL和SQL数据库的比较: 电商场景解决方案 Redis简介 Redis特性 Redis 优势 Redis应用场景 官方文 ...

  2. 树上分治详解 超级详细(附带例题 poj1741(给了题目))

    例题大概意思就是有一颗有 n 个顶点的树,其中连接顶点 a_i 和 b_i 的边 i 的长度为 l ,然后统计最短距离不超过 k 的顶点的对数 (虽然篇幅比较长,但是看完会有收获的) 树上的分治,与其 ...

  3. 平面分治详解 超级详细(附带例题 最近点对问题(给了题目))(UVA10245,P1257,P1429)

    最近点对问题,大概意思平面有n个点,求距离最近的两个点对的距离(可用平面分治解决绝大部分情况) 首先如果一个一个比较,那就是n的二次方复杂度,那很多情况都会超时 我们考虑使用分治法,大概思路就是将这个 ...

  4. Spring AOP全面详解(超级详细)

    如果说IOC 是 Spring 的核心,那么面向切面编程AOP就是 Spring 另外一个最为重要的核心@mikechen AOP的定义 AOP (Aspect Orient Programming) ...

  5. Java基本注解详解(超级详细)

    原文链接: 今日头条 Java注解是一个很重要的知识点,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注解. 掌握好Java注解有利于学习框架底层实现.@mikechen Ja ...

  6. 最小路径覆盖详解 超级详细(附带例题 Stock Charts(给了题目))

    最小路径覆盖定义:在图G中找出一些路径,每条路径从起点走到终点,使所有点均被覆盖,且只被覆盖一次,选出的这些路径组成路径覆盖.如果找出最少的路径成为一个路径覆盖,则称为最小路径覆盖. 对于不包含圈的有 ...

  7. kickstart详解(超级详细)

    一.kickstart是什么   许多系统管理员宁愿使用自动化的安装方法来安装红帽企业 Linux.为了满足这种需要,红帽创建了kickstart安装方法.使用kickstart,系统管理员可以创建一 ...

  8. 有向图最长路径算法_算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法...

    强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...

  9. poj2186(强连通分量分解)

    题目大概意思为有 N 头牛,有些牛认为有些牛是红人,该关系具有传递性,例如果牛A觉得牛B是红人,牛B认为牛C是红人,则牛A也会认为牛C是红人,求被其他所有牛认为是红人的牛的总数 假设被其他所有牛认为是 ...

最新文章

  1. 40亿次仿真学习:人工智能5:0大胜人类飞行员
  2. 腾讯云上午突发故障 称运营商光缆中断所致
  3. 大数据创业难度大 五个值得关注的重点
  4. MySQL Server 5.0安装教程
  5. 如何一步一步用DDD设计一个电商网站(十三)—— 领域事件扩展
  6. 「澳洋主数据项目」主数据促企业变革
  7. POJ1088(记忆搜索加dp)
  8. 几种常用网页返回顶部的代码
  9. 发现同济七版高等数学中的一处疑似错误
  10. 喜马拉雅xm格式转化mp3_毛毛虫点读笔如何点小达人点读书——小达人点读包dab转换成MP3切割音频...
  11. 如何理解IT、OT、CT?
  12. Play framework REST API
  13. 蓝桥杯2020年第十一届C/C++B组(第一次)省赛习题题解
  14. 帆软中的日期函数,当月第一天,当年第一天,当月最后一天等
  15. 【程序员股民系列】如何用python, pandas, numpy, matplotlib绘制每日行业成交额图
  16. Python取多维数组第n维的前几位
  17. Ubuntu使用自带的Liboffice Draw去除PDF水印
  18. win10 mysql 1030_Win10系统打开按键精灵提示#1030:启动脚本执行(图)
  19. PDF有密码,如何编辑密码?
  20. 【企业架构设计实战】企业架构方法论

热门文章

  1. 适兕:成为开源布道师
  2. 90后姑娘因熬夜长出老年斑吓坏网友!拯救熬夜党,智能家居也能出份力?
  3. 视频中的声音如何处理,如何添加背景音乐?
  4. 移动硬盘使用mysql_移动硬盘如何正确使用才好?
  5. 高手速成android开源项目[View篇]
  6. 科学论文的写作内容与要求
  7. md5update java_JAVA实现MD5算法
  8. 迭代最小二乘拟合椭圆
  9. windows如何查看内存条型号信息cpu型号信息 # 包括 内存条个数 和 cpu个数
  10. MODBUS RTU 协议读卡器