有向图的连通分量的求解思路

kosaraju算法

逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下

原博客https://www.cnblogs.com/nullzx/p/6437926.html

关于连通分量是什么自行百度,这里主要说明连通分量的求解方法

基本思路:第一次DFS得出顶点的顺序,根据顶点顺序进行第二次DFS,也就是逆后序遍历(手动模拟一下堆栈就知道第二次DFS的过程就能得出答案)。

为什么要两次DFS?

如果从连通分量A中任意一个定点DFS,得不到正确结果。应该按照被指向的强连通分量的定点排在前面的顺序进行DFS。上图按照B3,B4,B5,A0,A1,A2的顺序DFS。实际中我们只要保证被指向的强连通分量的至少一个顶点排在指向这个连通分量的所有顶点前面即可,比如B3,A0,A1,A2,B4,B5;B3排在强连通分量A所有定点的前面。

如何得到满足要求的顶点顺序:对原图取反,从反向图的任意节点开始进行DFS的逆后序遍历

DFS的逆后序遍历指:如果当前顶点没被访问,先遍历完与当前顶点相连的且未被访问的所有其他顶点,然后将当前顶点加入栈,最后从栈顶到栈底的顺序是我们需要的顶点顺序。

其实它是利用了有向图的方向性:例如在上图中,强连通分量A和B不管正反图都能自己跑一圈,但是从A到B就只能从A2跑到B3,不可能从B3跑到A2,所以将图取反(注意图取反,不能从A2跑到B3,顶点顺序被记录,按顶点顺序一个个弹出遍历,之前遍历过的点就不用再遍历),做成反向图,再逆后序遍历,A0在栈顶,遍历一圈,不能从A2跑到B3,就得到一个连通分量(如下图)

接下来原博主的代码看不懂,还是百度百科kosaraju算法里面的代码好

 #include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <stack>
#include <algorithm>
using namespace std;
#define INF 999999999
#define MAXN 551
#define MOD 1000000009
int n;
int mp[MAXN][MAXN], nmp[MAXN][MAXN], vis[MAXN];
stack<int> s;
void dfs_1(int v)
{
// cout << v <<endl;
vis[v] = ;
for(int i = ; i <= n; ++i)
if(!vis[i] && mp[v][i])
dfs_1(i);
s.push(v);
}
void dfs_2(int v)
{
vis[v] = ;
for(int i = ; i <= n; ++i)
if(!vis[i] && nmp[v][i])
dfs_2(i);
}
int kosaraju()
{
while(!s.empty())
s.pop();
memset(vis, , sizeof(vis)); for(int i = ; i <= n; ++i)
if(!vis[i])
dfs_1(i); int ans=;
memset(vis, , sizeof(vis)); while(!s.empty())
{
int v = s.top();
s.pop();
if(!vis[v])
{
// cout << v <<endl;
ans++;
dfs_2(v);
}
}
return ans;
}
int main()
{
int m, a, b;
//n个点,m条边
cin >> n >>m;
memset(mp, , sizeof(mp));
memset(nmp, , sizeof(nmp));
for(int i = ; i < m; ++i)
{
cin >> a >>b;
mp[a][b] = ;
nmp[b][a] = ;
}
cout << kosaraju() <<endl;
return ;
}
/*
5 5
1 2
2 1
2 3
3 4
4 1
样例输出:
2
*/

tarjan算法

这个算法网上很容易找到详解,其实认真看一遍百度百科也就懂得七七八八了

再附详解地址,这位博主也是转别人的,但是那个别人的博客打不开了

https://blog.csdn.net/qq_34374664/article/details/77488976

这个算法的核心思想:将连通分量的各个点用一个点表示。

 #include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <stack>
#include <algorithm> using namespace std; #define INF 0x3f3f3f3f
#define MAXN 551 int DFN[MAXN], Low[MAXN];
int vis[MAXN], sta_ck[MAXN];
int Index, cnt, tot;
int n; struct Node
{
int to;
int next;
}node[MAXN];
int head[MAXN]; //用head作为头指针指向下一个结点下标,让next指向head指向的下标后,head指向该结点
void add(int x, int y)
{
node[++cnt].next = head[x];
node[cnt].to = y;
head[x] = cnt;
} void tarjan(int x)
{
DFN[x] = Low[x] = ++tot;
sta_ck[++Index] = x;
vis[x] = ;
for(int i = head[x]; i != -; i = node[i].next)
{
if(!DFN[node[i].to])
{
tarjan(node[i].to);
Low[x] = min(Low[x], Low[node[i].to]);
}
else if(vis[node[i].to])
Low[x] = min(Low[x], DFN[node[i].to]);
}
if(Low[x] == DFN[x])
{
do
{
cout << sta_ck[Index] <<" ";
vis[sta_ck[Index]]=;
Index--;
}while(x != sta_ck[Index + ]);
cout << endl;
} } int main()
{
memset(head, -, sizeof(head));
memset(DFN, , sizeof(DFN));
memset(Low, , sizeof(Low));
int n, m;
cin >>n >>m;
int x, y;
for(int i = ; i <= m; ++i)
{
cin >>x >>y;
add(x, y);
}
for(int i = ; i <= n; ++i)
if(!DFN[i])
tarjan(i);
return ;
}

(转)求有向图的强连通分量个数(kosaraju算法)的更多相关文章

  1. 图论-求有向图的强连通分量(Kosaraju算法)

    求有向图的强连通分量     Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记. (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序 ...

  2. 求有向图的强连通分量个数 之 Kosaraju算法

    代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; ][] ...

  3. Tarjan算法 求 有向图的强连通分量

    百度百科 https://baike.baidu.com/item/tarjan%E7%AE%97%E6%B3%95/10687825?fr=aladdin 参考博文 http://blog.csdn ...

  4. Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量

    在此大概讲一下初学Tarjan算法的领悟( QwQ) Tarjan算法 是图论的非常经典的算法 可以用来寻找有向图中的强连通分量 与此同时也可以通过寻找图中的强连通分量来进行缩点 首先给出强连通分量的 ...

  5. Tarjan算法求有向图的强连通分量

    算法描述 tarjan算法思想:从一个点开始,进行深度优先遍历,同时记录到达该点的时间(dfn记录到达i点的时间),和该点能直接或间接到达的点中的最早的时间(low[i]记录这个值,其中low的初始值 ...

  6. 【数据结构】DFS求有向图的强连通分量

    用十字链表结构写的,根据数据结构书上的描述和自己的理解实现.但理解的不透彻,所以不知道有没有错误.但实验了几个都ok. #include <iostream> #include <v ...

  7. 算法-强连通分量和Kosaraju算法

    有向图中,连通性比较好理解,如果两个顶点V和顶点W是可达的,可以称之为强连通的,即存在路径A→B,同时也存在一条有向路径B→A.从之前的有向环的判定过程中其实我们可以得到一个结论就是两个是强连通的当且 ...

  8. 强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)

    poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且能够传递, 即1欢迎2不代表2欢迎1, 可是假设2也欢迎3那么1也欢迎3. 求 ...

  9. 有向图的强连通分量的求解算法Tarjan

    Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...

随机推荐

  1. 264E Roadside Trees

    传送门 题目大意 分析 倒着跑LIS表示以i为开头的LIS,于是对于删除可以暴力重算前10棵树.而对于种树,因为高度不超过10且高度两两不同,所以暴力重算比它矮的10棵树即可.对于需要重算的点,将其从 ...

  2. numpy.loadtxt() 出现codecError_____ Excel 做矩阵乘法

    1) 用 numpy读入csv文件是报错 UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal m ...

  3. mysql 游标CURSOR

    FETCH cursor_works INTO num,provinceIDs,cityIDs,SourceID; 定义的变量值必须与 游标中的字段不同,一一对应 DECLARE cursor_wor ...

  4. C# Socket通信改进记录

    1. Socket 使用原始Socket,Send和Recv方法 进行发送和消息获取.(另起后台线程 不停获取和发送) public void RecvMsg() { //receive messag ...

  5. C#Async,await异步简单介绍

    C# 5.0 引入了async/await,.net framework4.5开始支持该用法 使用: 由async标识的方法必须带有await,如果不带await,方法将被同步执行 static vo ...

  6. HTML4.0 需要掌握的主要内容

    常用标签: <html></html> 创建一个HTML文档 <head></head> 设置文档标题和其它在网页中不显示的信息 <title&g ...

  7. kali linux之edb--CrossFire缓冲区溢出

    漏洞的罪恶根源------变量,数据与代码边界不清,开发人员对用户输入没做过滤,或者过滤不严 如这个脚本,写什么,显示什么,但是加上:,|,&&,后面加上系统命令,就执行命令了 缓冲区 ...

  8. 洛谷P4494 [HAOI2018]反色游戏(tarjan)

    题面 传送门 题解 我们先来考虑一个联通块,这些关系显然可以写成一个异或方程组的形式,形如\(\oplus_{e\in edge_u}x_e=col_u\) 如果这个联通块的黑色点个数为奇数,那么显然 ...

  9. 1. UML统一建模语言

    (1)UML概述: 建模: 对现实系统进行适当的过滤, 用适当的表现规则描述出简洁的模型. 建模是一种深入解决问题的方法. UML: UML(United Modeling Language, 统一建 ...

  10. phpstudy下安装phalcon

    其实,一共也就下面几步,顺利的话,两分钟完事. 第一步:下载和当前php版本对应的php_phalcon.dll 文件 第二步:将此文件放到php版本下的ext里面. 第三步:在php.ini中添加如 ...