这个算法是自己实现的Kosaraju算法,附带一个缩点,其实缩点这个跟Kosaraju算法没有什么关系,应该其他的强连通分量算法计算出每个点所属的强连通分量之后也可以这样缩点。

算法复杂度:

Kosaraju算法:初始化,加边,两次dfs,复杂度O(n+m)

强连通分量缩点算法:遍历每个点每条边,复杂度O(n+m)

对边排序去重:复杂度O(n+mlogm)

注意:

1、最好先 Init() ,然后再 AddEdge()

2、维护缩点时点的性质对新点的影响在 dfs2() 中进行

3、维护缩点时边的性质对新点的影响在 Build() 中进行,特别注意缩点之后的自环

4、并不是每道题都需要原图反图,也并不是都需要对边进行去重

Kosaraju算法缩点的结果本身就是按拓扑序排列的。

namespace SCC {
int n;
vector<int> G[MAXN + 5], BG[MAXN + 5]; int c1[MAXN + 5], cntc1;
int c2[MAXN + 5], cntc2;
int s[MAXN + 5], cnts; int n2;
vector<int> V2[MAXN + 5];
vector<int> G2[MAXN + 5], BG2[MAXN + 5]; void Init(int _n) {
n = _n;
cntc1 = 0, cntc2 = 0, cnts = 0;
for(int i = 1; i <= n; ++i) {
G[i].clear();
BG[i].clear();
c1[i] = 0;
c2[i] = 0;
s[i] = 0;
V2[i].clear();
G2[i].clear();
BG2[i].clear();
}
return;
} void AddEdge(int u, int v) {
G[u].push_back(v);
BG[v].push_back(u);
return;
} void dfs1(int u) {
c1[u] = cntc1;
for(auto &v : G[u]) {
if(!c1[v])
dfs1(v);
}
s[++cnts] = u;
} void dfs2(int u) {
V2[cntc2].push_back(u);
c2[u] = cntc2;
for(auto &v : BG[u]) {
if(!c2[v])
dfs2(v);
}
return;
} void Kosaraju() {
for(int i = 1; i <= n; ++i) {
if(!c1[i]) {
++cntc1;
dfs1(i);
}
}
for(int i = n; i >= 1; --i) {
if(!c2[s[i]]) {
++cntc2;
dfs2(s[i]);
}
}
return;
} void Build() {
n2 = cntc2;
for(int i = 1; i <= n2; ++i) {
for(auto &u : V2[i]) {
for(auto &v : G[u]) {
if(c2[v] != i) {
G2[i].push_back(c2[v]);
BG2[c2[v]].push_back(i);
}
}
}
}
for(int i = 1; i <= n2; ++i) {
sort(G2[i].begin(), G2[i].end());
G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
sort(BG2[i].begin(), BG2[i].end());
BG2[i].erase(unique(BG2[i].begin(), BG2[i].end()), BG2[i].end());
}
return;
} void Solve() {
for(int i = 1; i <= n2; ++i) {
for(auto &u : V2[i]) {
//把原图的信息传递给新图;
}
}
//在新图上Solve;
return;
}
}

好像在不开O2的情况下这个vector版的比链式前向星版的费多了很多时间。

使用方法:

  1. Init,传入原图的点数。
  2. 使用AddEdge逐个加入有向边
  3. 调用Kosaraju划分强连通分量(V2存储强连通缩点后的新点包含原图的哪些点,c2存储原图的点对应强连通缩点后的哪个新点)。
  4. 调用Build在强连通缩点之后的新点之间建立新边到G2,并排序去重。
  5. 在Solve中书写在DAG中求解的代码,例如先把原图的点的信息传递给强连通缩点后的新点,然后在DAG上dp(注意是使用G2)。

模板 - 图论 - 强连通分量 - Kosaraju算法的更多相关文章

  1. 有向图的强连通分量——kosaraju算法

    一.前人种树 博客:Kosaraju算法解析: 求解图的强连通分量

  2. 图论-强连通分量-Tarjan算法

    有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...

  3. 图的强连通分量-Kosaraju算法

    输入一个有向图,计算每个节点所在强连通分量的编号,输出强连通分量的个数 #include<iostream> #include<cstring> #include<vec ...

  4. NOIP专题复习3 图论-强连通分量

    目录 一.知识概述 二.典型例题 1.[HAOI2006]受欢迎的牛 2.校园网络[[USACO]Network of Schools加强版] 三.算法分析 (一)Tarjan算法 (二)解决问题 四 ...

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

    在https://www.byvoid.com/zhs/blog/scc-tarjan中关于Tarjan算法的描述非常好,转述如下: 首先解释几个概念: 有向图强连通分量:在有向图G中,如果两个顶点间 ...

  6. 【模板】强连通分量和tarjan算法

    看了好久才终于明白了这个算法..复杂度是O(n+m). 我觉得这个算法不是很好理解,但是看懂了以后还是觉得听巧妙的. 下面给出模板代码和三组简单数据帮助理解. 代码如下: #include <s ...

  7. 模板 - 强连通分量 - Kosaraju

    Kosaraju算法 O(n+m) vector<int> s; void dfs1(int u) { vis[u] = true; for (int v : g[u]) if (!vis ...

  8. 算法模板——Tarjan强连通分量

    功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量 原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点 这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有 ...

  9. 强连通分量-----Kosaraju

    芝士: 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connect ...

随机推荐

  1. Linux ass2srt

    Linux ass2srt bash script #! /usr/bin/env bash ] then echo "USAGE: $0 <directory> <fro ...

  2. split()方法 splice()方法 slice()方法

    split()方法是对字符串的操作:splice()和slice()是对数组的操作.slice()也可用于字符串. 一.作用对象 1.split()方法是对字符串的操作:splice()和slice( ...

  3. 1+X证书学习日志——DOM节点的获取

    var oBox = document.getElementById('box');//获取ID为box的节点 var aBox = document.getElementsByTagName('di ...

  4. Python简单的CTF题目hash碰撞小脚本

    Python简单的CTF题目hash碰撞小脚本 import hashlib for num in range(10000,9999999999): res = hashlib.sha1(str(nu ...

  5. iview carousel 图片不显示;iview 轮播图 图片无法显示(转载)

    转载来源:https://segmentfault.com/q/1010000016778108 相关代码 <Carousel autoplay v-model="value2&quo ...

  6. python selenium八大定位方法

    一.定位方法 注意:元素属性必须唯一存在 #id定位 find_element_by_id() #name定位 find_element_by_name() #class_name定位 find_el ...

  7. RestTemplate对象,进行get和post简单用法

    如果只是针对纯Rest接口处理的话,我们可以使用restTemplate对象来操作,简单方便,可以不需要手写httpClient代码了. 我们看下基本的用法,如下: 1.getForObject cl ...

  8. C++中string::find()函数和string::npos函数的使用

    1. string::find()函数和string::npos函数的介绍 我们在学习C++的时候必不可少的使用到string类中的find()函数,它是一个查找函数,功能还是很强大的,但是此处我们不 ...

  9. GCC使用总结

    概念 GCC一开始是linux系统集成的用来编译C程序的编译器(GNU C Compiler),目前GCC已经不仅仅支持C语言了,因而其缩写名单意义也变成(GNU Compiler Collectio ...

  10. Oracle数据库使用游标查询结果集所有数据

    --Oracle使用游标查询结果集所有数据 DECLARE myTabelName NVARCHAR2():=''; --表名 myTableRowComment NVARCHAR2():=''; - ...