本文利用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实现具体代码:

SCC-pythonimport sys,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)