Kosaraju算法——强连通分量

′有向图的极大强连通子图,称为强连通分量。

′子图指的是选取V的一个子集V’,以及E当中所有满足u,v∈V’的边集E’所指代的图.

′我们需要找出一幅有向图当中的所有强连通分量。

′一个最朴素的算法:

′构造一个传递闭包(也就是数组Aij表示i能否到达j),然后把Aij=Aji=1的节点置于同一个强连通分量当中

′这个算法的复杂度是O(n^3),优点是代码复杂度小,缺点是速度太慢了

′这个算法原理和上面的方法是类似的,如果A能到达B并且B能到达A,那么A和B在同一个强连通分量里面。

′也可以等同于说,如果原图与逆图中A都能到达B,那么A与B在同一个强连通分量里面。

′逆图,指的是将原本有向图的所有边的方向变成相反,也就是说原本从a到b的边变成从b到a。

′算法流程有三步:

′对原图进行DFS,求出每一个节点的结束时间戳(离开这个节点时访问了多少个节点);

′选择结束时间戳最晚的节点,在逆图中进行遍历,删除能遍历到的节点,这些节点构成一个强连通分量;

′如果还有顶点未删除,重复第二步;

#include <bits/stdc++.h>
using namespace std;

const int maxn=100000+15;
int n,m;
vector <int> edge[maxn],rev[maxn];
int tim,rank[maxn],ref[maxn];
bool boo[maxn];
int color[maxn],tot;
int dfs1(int now)
{
    if (boo[now]) return 0;
    boo[now]=true;
    for (int i=0;i<edge[now].size();dfs1(edge[now][i]),i++);
    rank[now]=++tim;
    ref[tim]=now;
    return 0;
}
int dfs2(int now)
{
    if (color[now]!=0) return 0;
    color[now]=tot;
    for (int i=0;i<rev[now].size();dfs2(rev[now][i]),i++);
    return 0;
}
int main()
{
    freopen("ko.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        edge[x].push_back(y);
        rev[y].push_back(x);
        }
    for (int i=1;i<=n;i++)
     if (!boo[i]) dfs1(i);
    for (int i=n;i>=1;i--)
     if (color[ref[i]]==0)
     {
            tot++;
            dfs2(ref[i]);
            }
    for (int i=1;i<=n;i++)
     printf("%d ",color[i]);
    return 0;
}
时间: 2024-10-07 06:13:23

Kosaraju算法——强连通分量的相关文章

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

有向图中,连通性比较好理解,如果两个顶点V和顶点W是可达的,可以称之为强连通的,即存在路径A→B,同时也存在一条有向路径B→A.从之前的有向环的判定过程中其实我们可以得到一个结论就是两个是强连通的当且仅当它们都在一个普通的有向环中.强连通将所有的顶点分为了不同的集合,每个集合都是由相互均为强连通性的顶点的最大子集组成的,我们将这些集合称之为强连通分量. 基础概念 一般来说技术服务于生活,如果将我们看到网页作为顶点,页面指向另外一个页面的超链接作为边,可以将数量庞大的网页分为不同的大小进行处理,作

tarjan算法——强连通分量

简述: 用dfn作为时间戳,对图进行dfs并对路径上的点入栈,求出每个点可以访问到的最早的时间戳,此时栈中从这个点开始的点便为一个强连通分量. 模板: 1 void tarjan(int x,int lay,int &sccnum) { 2 low[x]=lay; 3 dfn[x]=lay; 4 vis[x]=1; 5 sta[++cnt]=x; 6 for(int i=head[x];~i;i=e[i].net) { 7 int v=e[i].v; 8 if(!vis[v]) tarjan(v

强连通分量的Tarjan算法

资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tarjan算法详解理解集合 ppt图解分析下载 强连通分量 强连通分量(strongly connected component)是图论中的概念.图论中,强连通图指每一个顶点皆可以经由该图上的边抵达其他的每一个点的有向图.意即对于此图上每一个点对(Va,Vb),皆存在路径Va→Vb以及Vb→Va.强连通

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

[图论] 有向图强连通分量 (kosaraju算法,Tarjan算法)

记录自己的想法:在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量.在用kosaraju算法和Tarjan算法求强连通分量的时候,就是给所有的顶点分组染色,同一种颜色的顶点在同一个强连通分量中,记录有多少种颜色(有多少个强联通分量),每个顶点属于哪种颜色(每个顶点在哪个强连通分量重).在同一个强连通分量中的所有顶点可以缩为一个顶点,然后根据缩点构造DAG(有向无环图

poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所

图论算法之(强连通分量&lt;Kosaraju&gt;)

强连通分量算法有3个之多,现在介绍这种名字叫做kosaraju算法. 这个算法基于两个事实,1.原图G与逆置图GT拥有相同的强连通分量,这肯定是正确的 2.任意一个子节点存放皆后于父节点,也就是说所有只有当所有子节点都入栈了,父节点才入栈 这种在递归调用之后将顶点入队列的方式叫逆后续排序(reverse post),在无环图中这种排序方式就是拓扑排序. 简要证明: 1. 第一次DFS有向图G时,最后记录下的节点必为最后一棵生成树的根节点. 证明:假设最后记录下节点不是树根,则必存在一节点为树根,

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

poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且可以传递, 即1欢迎2不代表2欢迎1, 但是如果2也欢迎3那么1也欢迎3. 求被所有牛都欢迎的牛的数量. 限制: 1 <= N <= 10000 1 <= M <= 50000 思路: Kosaraju算法, 看缩点后拓扑序的终点有多少头牛, 且要判断是不是所有强连通分量都连向它. Kosaraju算法,分拆完连通分量后,也完成了拓扑序. /*poj 2186

【Algorithms IV】求解强连通分量 Kosaraju算法

[Algorithms IV]求解强连通分量 Kosaraju算法 Kosaraju算法(也被称为Kosaraju–Sharir算法)是一个在线性时间内寻找一个有向图中的强连通分量的算法. 这个拗口的名字来自他的作者,但是查不到他的生平.应该是个印度人. 求解问题:要求有向图中的强连通分量的个数/划分 算法步骤: 即: 对输入G, 反转边获得逆向图GR     用DFS算法对图遍历得到reversePost序列(遍历图后push 到一个stack里,之后stack逆序弹出) 依次对reverse