前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >浅析强连通分量 Tarjan

浅析强连通分量 Tarjan

作者头像
用户2965768
发布于 2019-06-15 09:37:36
发布于 2019-06-15 09:37:36
86200
代码可运行
举报
文章被收录于专栏:wymwym
运行总次数:0
代码可运行

写的巨好:源地址

理解

在有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图。

定理: 1、一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个节点一次。

代码语言:txt
AI代码解释
复制
        **2、非强连通有向图的极大强连通子图,称为强连通分量(SCC即Strongly Connected Componenet)。**

在上图中,{1,2,3,4}是一个强连通分量,{5},{6}分别是另外两个强连通分量。怎么判断一个图是否是强连通图,如果不是,有哪些强连通分量,又怎么使它成为强连通图呢?

Tarjan算法

理解:

  Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。总的来说, Tarjan算法基于一个观察,即:同处于一个SCC中的结点必然构成DFS树的一棵子树。 我们要找SCC,就得找到它在DFS树上的根。

算法思想如下:

   dfnu表示dfs时达到顶点u的次序号(时间戳),lowu表示以u为根节点的dfs树中次序号最小的顶点的次序号,所以当dfnu=lowu时,以u为根的搜索子树上所有节点是一个强连通分量。 先将顶点u入栈,dfnu=lowu=++idx,扫描u能到达的顶点v,如果v没有被访问过,则dfs(v),lowu=min(lowu,lowv),如果v在栈里,lowu=min(lowu,dfnv),扫描完v以后,如果dfnu=lowu,则将u及其以上顶点出栈。

图解(一定要仔细从左往右看):

例题

模板(Tarjan算法)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void tarjan(int pos){
    vis[stack[++index]=pos]=1;//入栈并标记
    LOW[pos]=DFN[pos]=++dfs_num;
    for(int i=pre[pos];i;i=E[i].next){
        if(!DFN[E[i].to]){
            tarjan(E[i].to);
            LOW[pos]=min(LOW[pos],LOW[E[i].to]);
        }
        else if(vis[E[i].to]) LOW[pos]=min(LOW[pos],DFN[E[i].to]);
    }
    if(LOW[pos]==DFN[pos]){
        vis[pos]=0;
        size[dye[pos]=++CN]++;//染色及记录强连通分量大小
        while(pos!=stack[index]){
            vis[stack[index]]=0;
            size[CN]++;//记录大小
            dye[stack[index--]]=CN;//弹栈并染色
        }
        index--;
    }
}

模板(完整Tarjan):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
int n,m,idx=0,k=1,Bcnt=0;
int head[100];
int ins[100]={0};
int dfn[100]={0},low[100]={0};
int Belong[100];
stack <int> s;
struct edge
{
    int v,next;
}e[100];
int min(int a,int b)
{
    return a<b?a:b;
}
void adde(int u,int v)
{
     e[k].v=v;
     e[k].next=head[u];
     head[u]=k++;
}
void readdata()
{
     int a,b;
     memset(head,-1,sizeof(head));
     scanf("%d%d",&n,&m);
     for(int i=1;i<=m;i++)
     {
         scanf("%d%d",&a,&b);
         adde(a,b);
     }
}
void tarjan(int u)
{
     int v;
     dfn[u]=low[u]=++idx;//每次dfs,u的次序号增加1
     s.push(u);//将u入栈
     ins[u]=1;//标记u在栈内
     for(int i=head[u];i!=-1;i=e[i].next)//访问从u出发的边
     {
         v=e[i].v;
         if(!dfn[v])//如果v没被处理过
         {
             tarjan(v);//dfs(v)
             low[u]=min(low[u],low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
         }
         else if(ins[v])low[u]=min(low[u],dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
     }     
     if(dfn[u]==low[u])
     {
         Bcnt++;
         do
         {
             v=s.top();
             s.pop();
             ins[v]=0;
             Belong[v]=Bcnt;
         }while(u != v);
     }
}
void work()
{
     for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
     printf("\n");
     for(int i = 1;i <= 6;i++)printf("%d %d\n",dfn[i],low[i]);
     printf("共有%d强连通分量,它们是:\n",Bcnt); 
     for(int i=1;i<=Bcnt;i++)
     {
        printf("第%d个:",i);
        for(int j=1;j<=n;j++)
        {
           if(Belong[j]==i)printf("%d ",j);
        }
        printf("\n");
     }
}
int main()
{
    readdata();
    work();
    return 0;
}
/*
6 8 
1 2
1 3
2 4
3 4
3 5
4 1
4 6 
5 6
*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年04月11日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
TarJan 算法求解有向连通图强连通分量
在有向图G中,如果两个 顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
RainMark
2019/09/10
1.9K0
TarJan 算法求解有向连通图强连通分量
Tarjan 算法求解强连通分量
在 《Tarjan 算法的思路》中我们已经给出了 Tarjan 算法中的比较重要的几个元素,我们在这里重新复习一下:
用户2932962
2019/07/27
1.2K0
Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法
一、背景介绍 强连通分量是有向图中的一个子图,在该子图中,所有的节点都可以沿着某条路径访问其他节点。强连通性是一种非常重要的等价抽象,因为它满足 自反性:顶点V和它本身是强连通的 对称性:如果顶点V和顶点W是强连通的,那么顶点W和顶点V也是强连通的 传递性:如果V和W是强连通的,W和X是强连通的,那么V和X也是强连通的 强连通性可以用来描述一系列属性,如自然界中物种之间的捕食关系,互相捕食的物种可以看作等价的,在自然界能量传递中处于同一位置。 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,
老白
2018/03/19
2.8K0
Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法
Tarjan算法求图的强连通分量
   有向图强连通分量:在有向图 G 中,如果两个顶点 V_i, V_j 间(vi>vj)有一条从 V_i 到 V_j 的有向路径,同时还有一条从 V_j 到 V_i 的有向路径,则称两个顶点强连通 (strongly connected)。如果有向图 G 的每两个顶点都强连通,称 G 是一个强连通图。有向图的极大强连通子图,称为强连通分量 (strongly connected components)。
yhlin
2023/02/27
1.4K0
Tarjan算法求图的强连通分量
POJ2186 Popular Cows 【强连通分量】+【Kosaraju】+【Tarjan】+【Garbow】
Every cow’s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
全栈程序员站长
2022/07/08
1930
ccf 高速公路(连通子图)
  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。   现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。   国王想知道,在大臣们给他的计划中,有多少个便利城市对。
用户1148523
2019/05/26
8890
hdu 4635 Strongly connected (tarjan)
题意:给一个n个顶点m条弧的简单有向图(无环无重边),求最多能够加入多少条弧使得加入后的有向图仍为简单有向图且不是一个强连通图。假设给的简单有向图本来就是强连通图,那么输出-1. 分析: 1.用tarjan算法求出强连通分量的个数,假设个数为1,那么输出-1,结束,否则运行2 2.如果将一些强连通分量合并为有n1个顶点简单全然图1,而将剩下的强连通分量合并为n2个顶点的简单全然图2,跨这两个简单全然图的弧的方向仅仅能是单向的,如果m1为全然图1内部的弧的数量,m2为为全然图2内部的弧的数量。m3为跨这两个简单全然图的弧的数量,那么 ans=n1*(n1-1)-m1+n2*(n2-1)-m2+n1*n2-m3 —————————————————-1式 n1+n2=n —————————————————-2式 m1+m2+m3=m —————————————————-3式 n*n=(n1+n2)(n1+n2)=n1*n1+n2*n2+2*n1*n2 —————————————————–4式 所以 ans=n*n-m-n-n1*n2=n*n-m-n-n1*(n-n1) ans要最大,所以n1*(n-n1)要最小。同一时候要跨图1。图2的弧要单向, 所以在跨图1,图2的弧要单向的情况下。n1尽量小。
全栈程序员站长
2022/07/08
2200
tarjan算法详解
tarjan算法讲解。 tarjan算法,一个关于 图的联通性的神奇算法。基于DFS算法,深度优先搜索一张有向图。!注意!是有向图。根据树,堆栈,打标记等种种神奇方法来完成剖析一个图的工作。而图的联通性,就是任督二脉通不通。。的问题。 了解tarjan算法之前你需要知道: 强连通,强连通图,强连通分量,解答树(解答树只是一种形式。了解即可) 强连通(strongly connected): 在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,
attack
2018/04/12
1.9K0
tarjan算法详解
算法数据结构 | 20行代码实现,使用Tarjan算法求解强连通分量
在开始文章之前先跟大家同步一个坏消息,大概是由于整理了PDF分享的原因,遭到leetcode上海官方投诉侵权(虽然我一直用的都是海外版)。我个人觉得这种行为非常霸道,决定以后不再更新leetcode相关的文章,并且之前的文章也进行了删除。对于想要看这部分文章的朋友,先说声非常抱歉。周末我会寻找其他平台的算法问题作为替代,带来不便,再次抱歉。
TechFlow-承志
2020/09/03
6810
Tarjan算法
tarjan算法 一个关于有向图的联通性的神奇算法。 基于DFS(迪法师)算法,深度优先搜索一张有向图。 名词的储备,有备无患 强连通(strongly connected): 在一个有向图G里,设两个点 a、b。发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。 强连通图(Strongly Connected Graph): 如果在一个有向图G中,每两个点都强连通,我们就叫这个图,强连通图。 强连通分量(strongly connected c
机器学习算法工程师
2018/03/06
8750
Tarjan算法
图的连通性问题专题整理
这一篇博客继续以一些OJ上的题目为载体,对图的连通性专题进行整理一下。会陆续的更新。。。
全栈程序员站长
2022/07/13
4380
有向图强连通分量SCC(全网最好理解)
在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量。
风骨散人Chiam
2020/10/28
1.4K0
有向图强连通分量SCC(全网最好理解)
Tarjan算法
SCC即强连通分量,即一个图的子图,其中的点能相互到达,全称是strongly connected component。
饶文津
2020/06/02
5980
C++图论之强连通图
连通,字面而言,类似于自来水管道中的水流,如果水能从某一个地点畅通流到另一个地点,说明两点之间是连通的。也说明水管具有连通性,图中即如此。
一枚大果壳
2023/12/26
2650
C++图论之强连通图
367. 学校网络(Tarjan强连通分量)[通俗易懂]
一些学校连接在一个计算机网络上,学校之间存在软件支援协议,每个学校都有它应支援的学校名单(学校 A 支援学校 B,并不表示学校 B 一定要支援学校 A)。
全栈程序员站长
2022/09/22
3910
算法模板——Tarjan强连通分量
功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量 原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点 这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有向图可以有效的进行缩点(每个强连通分量缩成一个点),构成一个新的拓扑图(如BZOJ上Apio2009的那个ATM)(PS:注意考虑有些图中不能通过任意一个单独的点到达全部节点,所以不要以为直接tarjan(1)就了事了,还要来个for循环,不过实际上复杂度还是O(M),因为遍历过程中事实上每个边还是只会被走一次
HansBug
2018/04/10
6560
[Tarjan/最大连通分量] P1726 上白泽慧音
在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。
用户7267083
2022/12/08
3650
[Tarjan/最大连通分量] P1726 上白泽慧音
《python算法教程》Day7 - 获取有向图的所有强连通分量强连通分量定义代码示例
今天是《python算法教程》的第7篇读书笔记,笔记的主要内容是通过python的遍历方式找出有向图的强连通分量。 强连通分量定义 在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到v
billyang916
2018/05/02
2K0
《python算法教程》Day7 - 获取有向图的所有强连通分量强连通分量定义代码示例
tarjan算法
     说到以Tarjan命名的算法,我们经常提到的有3个,其中就包括本文所介绍的求强连通分量的Tarjan算法。而提出此算法的普林斯顿大学的Robert E Tarjan教授也是1986年的图灵奖
triplebee
2018/01/09
1K0
tarjan算法
算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法
今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法。
TechFlow-承志
2020/09/01
9120
推荐阅读
相关推荐
TarJan 算法求解有向连通图强连通分量
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验