本文利用Kosaraju’s Two-Pass Algorithm 解决强连通子图问题。
Kosaraju算法是求解有向图强连通分量(strong connected component)的三个著名算法之一(另两个算法为Tarjan和Gabow),能在线性时间求解出一个图的强分量。三种算法具体的差别可参考:http://www.cppblog.com/koson/archive/2010/04/27/113694.html
什么是强连通分量?在这之前先定义一个强连通性(strong connectivity)的概念:有向图中,如果一个顶点s到t有一条路径,t到s也有一条路径,即s与t互相可达,那么我们说s与t是强连通的。那么在有向图中,由互相强连通的顶点构成的分量,称作强连通分量。
步骤概要:
1:在该图的逆图上运行DFS,将顶点按照后序编号的顺序放入一个数组中(显然,这个过程作用在DAG上得到的就是一个拓扑排序);
2:在原图上,按第一步得出的后序编号的逆序进行DFS。也就是说,在第二次DFS时,每次都挑选当前未访问的结点中具有最大后序编号的顶点作为DFS树的树根。
python实现具体代码:
![]()
time, threading
from collections
import defaultdict
sys.
setrecursionlimit(3000000)
threading.stack_size(2**27) # largest power of 2 that didn't give me an error, don't know what I needed
source='SCC.txt'
visited={}
finish={}
leader={}
t=0
s=0
def init(G):
visited.clear()
finish.clear()
leader.clear()
for i in list(G.keys()):
visited[i] = 0
finish[i] = 0
leader[i]=0
def getG():
G={}
Grev={}
fin=
open(source)
for line in fin:
v1=int(line.
split()[0])
v2=int(line.
split()[1])
G.setdefault(v1,[]).append(v2)
Grev.setdefault(v1,[])
Grev.setdefault(v2,[]).append(v1)
fin.
close()
return G, Grev
def time_excute():
start =
time.clock()
getG()
spend =
time.clock()-
start
return spend
def dfs(G, i):
global t
#
print(s)
visited[i]=1
leader[i]=s
for j in G[i]:
if j in visited and visited[j]==0:
visited[j]=1
dfs(G,j)
t=t+1
finish[i]=t
def dfs_loop(G):
global t
global s
t=0 #number of nodes processed so far
s=None #current source vertex
for i in sorted(list(G.keys()),reverse=True):
if i in visited and visited[i]==0:
s=i
dfs(G,i)
def getKeys(G,
index):
i = 0
#for i in range(len(G)):
s= list(G.keys())
#
print(s)
for i in range(len(s)):
if i ==
index:
#
print(s[i])
return s[i]
i+=1
return None
def main():
print("
load data时间:")
begin =
time.clock()
g, grev=getG()
print(
time.clock()-begin)
print("
第一次根据grev初始化状态值的时间:")
begin =
time.clock()
init(grev)
print(
time.clock()-begin)
print("
#################################")
print("
第一次defloop时间:")
begin =
time.clock()
dfs_loop(grev) #THE FIRST LOOP ON REVERSE GRAPH
print(
time.clock()-begin)
print("
根据visited建立newgraph时间:")
begin =
time.clock()
newGraph={}
for i in list(g.keys()):
temp=[]
for x in g[i]:
temp.append(finish[x])
newGraph[finish[i]]=temp
print(
time.clock()-begin)
print("
第二次根据newgraph初始化状态值的时间:")
begin =
time.clock()
init(newGraph)
print(
time.clock()-begin)
print("
#################################")
print()
print("
第二次defloop时间:")
begin =
time.clock()
dfs_loop(newGraph)
print(
time.clock()-begin)
print("
leader数组排序的时间:")
begin =
time.clock()
lst= sorted(leader.values())
print(
time.clock()-begin)
print("
#################################")
print("
#################################")
print("
#################################")
print()
stat=[]
pre=0
print("
根据leader数组获取强连通分量数目的时间:")
begin =
time.clock()
for i in range(0,len(newGraph)-1):
if lst[i]!=lst[i+1]:
stat.append(i+1-pre)
pre=i+1
stat.append(len(newGraph)-pre)
L= sorted(stat)
L.reverse()
print(
time.clock()-begin)
print("
最大5个强连通分量的数目为:")
print(L[0:5])
t1 = threading.Thread(target=main,args=()) # creates a thread to call my
function scc(graph)
begin =
time.clock()
t1.
start() #
start the scc thread
t1.
join() # and wait for it to finish
print('总的时间消耗为:')
print(
time.clock() - begin)