Barjar算法

 
Barjan 算法和inline流程
图的一些基本概念:
  • 关联(incident):点为边的端点;
  • 邻接(adjacent):点与点关联同一条边,或边与边关联同一顶点;
  • 子图:图G'的点和边都是图G的子集,则G'为G的子图;
  • 道路:从点v到点u的路径;
  • 简单道路:没有重复边的道路;
  • 回路:起点与终点相同的道路;
  • 简单回路:没有重复边的回路;
  • 连通:两顶点间有道路;
  • 强连通:有向图u→v与v→u都有道路;
  • 连通图:任意两顶点间都有道路(若有向图除去方向后连通,则称有向图连通);
  • 简单图:没有重复边和自环的图;
  • 完全图:任意两顶点间有一条边到达的简单图(有向完全图与无向完全图);
  • 强连通图: 如果有向图G 的每两个顶点都强连通,称G 是一个强连通图;
  • 强连通分量(strongly connected components): 非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
 
 
Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
  • 定义:
o DFN(u)为节点u 搜索的次序编号(时间戳);
o LOW(u)为u 或 u的子树能够追溯到的最早的栈中节点的次序号;
由定义可以得出,当 DFN(u)=LOW(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
  • 算法:
  1. 当首次搜索到点u时DFN[u]=LOW[u]=time;
  2. 每当搜索到一个点,把该点压入栈顶;
  3. 当u和v有边相连时:
1)如果v不在栈中(树枝边),DFS(v),并且LOW[u] = min{LOW(u),LOW(v)};
2)如果v在栈中(前向边/后向边),此时LOW[u] = min{LOW[u],DFN[v]}
  1. 当DFN[u]=LOW[u]时,将它以及在它之上的元素弹出栈,此时,弹出栈的结点构成一个强连通分量;
  2. 继续搜索,知道图被遍历完毕。
由于在这个过程中每个点只被访问一次,每条边也只被访问一次,所以Tarjan算法的时间复杂度是O(n+m).
 
1.从节点0开始DFS:
  • 代码(1)-(5): 得到访问链:0 -> 2 -> 4 -> 5, 把遍历到的4个节点{0, 2, 4, 5}加入栈中; 四个节点的LOW[] 和 DFN[]值, 依次被Index标注成1到4; 注: 这里也可以走另外一条路径: 0 -> 2 -> 3 -> 5;
  • 代码(9)-(13): 节点5的后续边已经遍历完成, 退出节点5时, 发现DFN[5] = LOW[5] = 4, 于是节点5出栈,{5}为一个强连通分量;
2.返回节点4:
  • 代码(6): LOW[4] = min(LOW[4], LOW[5]) = min(3, 4) = 3;
  • 代码(9)-(13): 节点4的后续边已经遍历完成, 退出节点4时, DFN[4] = LOW[4] = 3; 退栈到节点4出栈,{4}为一个强连通分量;
3.返回节点2:
  • 代码(6): LOW[2] = min(LOW[2], LOW[4]) = min(2, 3) = 2;
4.从节点2继续搜索到节点3:
  • 代码(4)-(5): 继续遍历节点2的后续边, 找到节点3;
  • 代码(1)-(2): 把3加入堆栈, Index = 5, DFN[3] = LOW[3] = 5;
  • 代码(3)-(8): 发现节点3向节点0有边(3 -> 0),且节点0在栈中,所以LOW[3] = min(LOW[3], DFN[0]) = min(5, 1) = 1。
  • 代码(3)-(8): 发现节点3向节点5有边(3 -> 5), 但节点5已出栈;
5.返回节点2;
  • 代码(6): LOW[2] = min(LOW[2], LOW[3]) = min(2, 1) = 1;
6.返回节点0;
  • 代码(6): LOW[0] = min(LOW[0], LOW[2]) = min(1, 1) = 1;
7.从节点0继续搜索到节点1;
  • 代码(1)-(2): 把1加入堆栈, Index = 6, DFN[1] = LOW[1] = 6;
  • 代码(3)-(8): 发现节点1向节点3有边(1 -> 3),且节点3还在栈中,所以LOW[1] = min(LOW[1], DFN[3]) = min(6, 5) = 5;
8.返回节点0;
  • 代码(9)-(13): 退出时发现DFN[0] = LOW[0] = 1, 退栈到节点0出栈,组成一个连通分量{1, 3, 2, 0}。
  • 最终, 所有节点和边都已经访问到, 得到所有连通分量: {5}, {4}, {1, 3, 2, 0}。
 
一个实际的inline访问的例子
SCC 联通子图
A extern{1,1}
B Add{2,2}
C Mul{3,3}
D main{4,4}
F printf{5,5}
子图获得顺序 B==》C==》F==》D===》A
节点遍历次序 Add==》Mul==》printf==》main===》extern
 
 
 
posted @ 2022-04-22 16:43  zzas12345  阅读(27)  评论(0编辑  收藏  举报