tarjan算法详解

https://blog.csdn.net/jeryjeryjery/article/details/52829142?locationNum=4&fps=1

以防链接失效,特此转载此博,如有侵权请见谅

 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。如下图中,强连通分量有:{1,2,3,4},{5},{6}

       Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。Tarjan算法有点类似于基于后序的深度遍历搜索和并查集的组合,充分利用回溯来解决问题。
在Tarjan算法中为每个节点i维护了以下几个变量:
DFN[i]:深度优先搜索遍历时节点i被搜索的次序。
low[i]:节点i能够回溯到的最早位于栈中的节点。
flag[i]:标记几点i是否在栈中。

Tarjan算法的运行过程:
(1).首先就是按照深度优先搜索算法搜索的次序对图中所有的节点进行搜索。
(2).在搜索过程中,对于任意节点u和与其相连的节点v,根据节点v是否在栈中来进行不同的操作:
*节点v不在栈中,即节点v还没有被访问过,则继续对v进行深度搜索。
*节点v已经在栈中,即已经被访问过,则判断节点v的DFN值和节点u的low值的大小来更新节点u的low值。如果节点v的 DFN值要小于节点u的low值,根据low值的定义(能够回溯到的最早的已经在栈中的节点),我们需要用DFN值来更新u 的low值。
(3).在回溯过程中,对于任意节点u用其子节点v(其实不能算是子节点,只是在深度遍历的过程中,v是在u之后紧挨着u的节点)的   low值来更新节点u的low值。因为节点v能够回溯到的已经在栈中的节点,节点u也一定能够回溯到。因为存在从u到v的直接路径,所以v能够到的节点u也一定能够到。

(4).对于一个连通图,我们很容易想到,在该连通图中有且仅有一个节点u的DFN值和low值相等。该节点一定是在深度遍历的过程中,该连通图中第一个被访问过的节点,因为它的DFN值和low值最小,不会被该连通图中的其他节点所影响。

      下面我们证明为什么仅有一个节点的DFN和low值相等。假设有两个节点的DFN值和low值相等,由于这两个节点的DFN值一定不相同 (DFN值的定义就是深度遍历时被访问的先后次序),所以两个的low值也绝对不相等。由于位于同一个连通图中,所以两个节点必定相互可达,那么两者的low值一定会被另外一个所影响(要看谁的low值更小),所以不可能存在两对DFN值和low值相等的节点。

       所以我们在回溯的过程中就能够通过判断节点的low值和DFN值是否相等来判断是否已经找到一个子连通图。由于该连通图中的DFN值和low值相等的节点是该连通图中第一个被访问到的节点,又根据栈的特性(先压入  栈的节点在栈的更里面),则该节点在最里面。所以能够通过不停的弹栈,直到弹出该DFN值和low值相同的节点来弹出该连通图中所有的节点。

 

Tarjan算法的C++实现代码如下,可以配合上面的图加以理解:

 

[cpp] view plaincopy
    1. #include<iostream>  
    2. using namespace std;  
    3. int DFN[105];                                  //记录在做dfs时节点的搜索次序  
    4. int low[105];                                  //记录节点能够找到的最先访问的祖先的记号  
    5. int count=1;                                   //标记访问次序,时间戳  
    6. int stack[105];                                //压入栈中  
    7. int top=-1;  
    8. int flag[105];                                 //标记节点是否已经在栈中  
    9. int number=0;  
    10. int j;  
    11. int matrix[105][105]={{0,1,1,0,0,0},{0,0,0,1,0,0},{0,0,0,1,1,0},{1,0,0,0,0,1},{0,0,0,0,0,1},{0,0,0,0,0,0}};  
    12. int length;                                    //图的长度  
    13. void tarjan(int u){  
    14.     DFN[u]=low[u]=count++;                     //初始化两个值,自己为能找到的最先访问的祖先  
    15.     stack[++top]=u;  
    16.     flag[u]=1;                                 //标记为已经在栈中  
    17.   
    18.     for(int v=0;v<length;v++){  
    19.     if(matrix[u][v]){  
    20.         if(!DFN[v]){                       //如果点i没有被访问过  
    21.         tarjan(v);                     //递归访问  
    22.         if(low[v]<low[u])  
    23.             low[u]=low[v];             //更新能找的到祖先  
    24.         }  
    25.         else{                              //如果访问过了,并且该点的DFN更小,则  
    26.         if(DFN[v]<low[u]&&flag[v])     //flag[v]这个判断条件很重要,这样可以避免已经确定在其他联通图的v,因为u到v的单向边而影响到u的low  
    27.         low[u]=DFN[v];                 //也就是已经确定了的联通图要剔除掉,剔除的办法就是判断其还在栈中,因为已经确定了的连通图的点  
    28.         }                                  //flag在下面的do while中已经设为0了(即已经从栈中剔除了)  
    29.     }  
    30.     }  
    31.   
    32.     //往后回溯的时候,如果发现DFN和low相同的节点,就可以把这个节点之后的节点全部弹栈,构成连通图  
    33.     if(DFN[u]==low[u]){  
    34.     number++;                               //记录连通图的数量  
    35.     do{  
    36.         j=stack[top--];                     //依次取出,直到u  
    37.         cout<<j<<" ";  
    38.         flag[j]=0;                          //设置为不在栈中  
    39.     }while(j!=u);  
    40.         cout<<endl;  
    41.     }  
    42. }  
    43. int main(){  
    44.       
    45.     memset(DFN,0,sizeof(DFN));                  //数据的初始化  
    46.     memset(low,0,sizeof(low));  
    47.     memset(flag,0,sizeof(flag));  
    48.       
    49.     length=6;  
    50.     tarjan(0);  
    51.   
    52.     cout<<endl;  
    53.     for(int i=0;i<6;i++){  
    54.     cout<<"DFN["<<i<<"]:"<<DFN[i]<<" low["<<i<<"]:"<<low[i]<<endl;  
    55.     }  
    56.     return 0;  
    57. }  

转载于:https://www.cnblogs.com/cglongge/p/8722202.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gitlab简单使用CI/CD

开篇语大概是去年就想做这个事情了&#xff0c;奈何当时卡到一个docker命令找不到的问题上&#xff0c;导致文章难产了&#xff0c;墨迹了这么久&#xff0c;终于又有空来捣鼓它了。目的我们要实现的目的是我本地不断提交代码(CI),然后服务器不断进行部署(CD)的一个简单流程。准…

AppleScript: Handler

AppleScript绝对是个奇葩的存在&#xff01;不管功能有多强大。 Handler有两种&#xff0c;一种是和OC类似的使用Label参数&#xff0c;一种是和javascript类似的使用括号把一堆参数都放在里面的。 label参数的Handler的写法非常奇怪&#xff0c;光看文档绝对让人迷糊。这里按照…

powershell 运行策略

Unrestricted 这是一种比较宽容的策略&#xff0c;允许运行未签名的脚本。对于从网络上下载的脚本&#xff0c;在运行前会进行安全性提示&#xff1a; Set-ExecutionPolicy UnRestricted

免费的数字图书馆_不仅是书籍:您当地图书馆可能提供的所有免费数字资料

免费的数字图书馆You might think of libraries as old fashioned, or irrelevant in the age of the internet. You’d be wrong. 您可能会认为图书馆是老式的&#xff0c;或者与互联网时代无关。 你会错的。 Modern libraries offer books, yes, but they also provide inter…

iNeuOS工业互联网操作系统,脚本化实现设备运行时长和效率计算与统计

目 录1. 概述... 22. 实时采集开停状态... 23. 增加虚拟设备... 24. 脚本统计和计算设备运行时长... 45. 设备运行时长报表... 71. 概述有一个煤矿项目&#xff0c;使用iNeuOS系统时有一个需要是&#xff1a;要统计设备的运行时长&#xff0c…

webpack二(以webpack4.x起步)

一.基本安装首先我们要创建一个目录&#xff0c;初始化npm&#xff0c;以及在本地安装webpack&#xff1a;复制代码mkdir webpackapp && cd webpackapp复制代码npm init -y复制代码npm install --save-dev webapck复制代码现在我们看一下我们创建的目录以及目录下的结构…

阿里云中间件是什么-阿里云中间件介绍

阿里云中间件是什么?这其实是一个比较虚的概念。广义的中间件范围很广。起沟通作用的都可以认为是中间件。甚至ODBC这样的东西你也可以认为是中间件。 使用了中间件之后&#xff0c;以前直接连接的前台应用程序和数据库之前就多了个中间件&#xff0c;现在前台程序把请求发给…

C# 图片、文件等加入Project Resources

一、目的 1.编译后&#xff0c;只想有一个exe文件&#xff0c;不想外部文件引用&#xff0c;直接运行exe文件即可。 2.不会出现文件丢失情况。 二、操作 1.右击project ->properties->Resource&#xff0c;左上角选择Image&#xff08;或其他类型&#xff09; 2. 点击…

jfinal使用shiro注解大体流程

2019独角兽企业重金招聘Python工程师标准>>> 上一篇答题梳理了jfinal整合shiro的流程&#xff0c;jfinal读取shiro注解&#xff0c;这一篇将作为补充。 1.JFinalShiroPlugin作者为shiro的RequiresRoles&#xff0c;RequiresPermissions&#xff0c; RequiresAuthent…

chrome 快捷键取消_如何使用键盘快捷键在Chrome和Firefox中固定和取消固定选项卡...

chrome 快捷键取消If you tend to open a lot of tabs in your browser, it can become difficult to find the tabs with your most used websites. Pinning tabs in your browser moves those tabs to the left and shrinks the tabs to only show the favicon, and you can …

.NET Conf China 2022参会指南速览(内含超多福利)赶紧预约!⏰⏰⏰

12月充满惊喜各种美好节日纷至沓来似在奖励一年辛苦劳作的你12月的第一波福利.NET Conf China 承包啦立即扫码预约加入.NET年度盛宴抢12月第一波惊喜&#xff01;.NET Conf China 2022 .NET Conf China 2022是面向开发人员的社区峰会&#xff0c;延续 .NET Conf 2022 的活动&a…

python导入模块--案例

1 导入模块 1.1 问题 本案例要求先编写一个star模块&#xff0c;主要要求如下&#xff1a; 建立工作目录 ~/bin/创建模块文件 ~/bin/star.py模块中创建pstar函数&#xff0c;实现打印50个星号的功能然后练习导入模块&#xff0c;调用模块中的函数&#xff1a; 在交互解释器中导…

css常用命名

常用的CSS命名 头&#xff1a;header 内容&#xff1a;content/container 尾&#xff1a;footer 导航&#xff1a;nav 侧栏&#xff1a;sidebar 栏目&#xff1a;column 页面外围控制整体佈局宽度&#xff1a;wrapper 左右中&#xff1a;left right center 登录条&#xff1a;l…

***关于WP的邮件无法发送问题的总结(原创)

1.用FTP打开 /wp-include/class-smtp.php &#xff0c;最好是下载下来&#xff0c;搜索一下&#xff0c;查找到如下的代码&#xff1a; $this->smtp_conn stream_socket_client($host . ":" . $port,$errno,$errstr,$timeout,STREAM_CLIENT_CONNECT,$socket_cont…

C# 简单方式运行powershell文件/使用cmd命令运行ps1

一、目的、构想 1.C# winfrom编译的tool 运行一个powershell文件。 2.只需要运行即可&#xff0c;不需要返回值。 3.网上部分资料需要额外添加dll。 3.已经有cmd执行命令的函数&#xff0c;能否直接在cmd运行&#xff1f; 4.在cmd黑色窗口输入powershell 能进入powershell…

​.Net 7 AOT 彻底解析下(完结篇)

楔子&#xff1a;本篇是承继前面三篇文章而来&#xff0c;分别为&#xff1a;.Net 7 的 AOT 和 CLR有什么区别&#xff1f;.Net 7 的 R2R,Crossgen2是什么?.Net 7 的AOT原理简析通过以上三篇的基础&#xff0c;本篇来彻底解析下AOT这门技术的底层原理。AOT此终&#xff0c;不再…

cmd暂停快捷键_是否有键盘快捷键可以暂停正在运行的CMD窗口的输出?

cmd暂停快捷键When running a batch script, you may need or want to pause the output in the CMD window so that you can look things over. Is there an easy way to pause, then restart the output? Today’s SuperUser Q&A post has the answer to help with a re…

bash快捷键

Ctrl h &#xff1a;回退一个字符Ctrl f &#xff1a;光标前进一个字符Ctrl b &#xff1a;光标后退一个字符Ctrl w &#xff1a;删除光标之前的一个字符串&#xff08;进入剪切板&#xff09;Ctrl u &#xff1a;删除光标前的所有字符 &#xff08;进入剪切板&#xff09…

J - 青蛙的约会(扩展欧几里得)

https://vjudge.net/contest/218366#problem/J 第一步追及公式要写对&#xff1a;ynk-(xmk)pL > (n-m)klpx-y 可以看出扩展欧几里得原型&#xff0c;这里注意扩展欧几里得求出的是任意解&#xff0c;非最优&#xff0c;要推出最小解k。 (n-m)xlygcd > (n-m)(x*(x-y)/gcd)…

C# 简单方式解压Zip文件/使用VS2019自带功能

一、目的、构想 1.直接解压zip文档。 2.网上资料不少需要外部dll。 3. 找到可以不需要外部dll方法&#xff0c;分享。 二、code实现 using System.IO.Compression;string filePath "c:\Server\fileList"; string zipPath "C:\Server\Download\Auto.zip&quo…