1. DFS判斷有向圖是否有環
假設圖以鄰接矩陣表示,一條深度遍歷路線中如果有結點被第二次訪問到,那麼有環。我們用一個變量來標記某結點的訪問狀態(未訪問,訪問過,其後結點都被訪問過),然後判斷每一個結點的深度遍歷路線即可。
def dfs(G,i,color):
r = len(G)
color[i] = -1
have_circle = 0
for j in range(r): # 遍歷當前節點i的所有鄰居節點
if G[i][j] != 0:
if color[j] == -1:
have_circle = 1
elif color[j] == 0:
have_circle = dfs(G,j,color)
color[i] = 1
return have_circle
def findcircle(G):
# color = 0 該節點暫未訪問
# color = -1 該節點訪問了一次
# color = 1 該節點的所有孩子節點都已訪問,就不會再對它做DFS了
r = len(G)
color = [0] * r
have_circle = 1
for i in range(r): # 遍歷所有的節點
if color[i] == 0:
have_circle = dfs(G,i,color)
if have_circle == 0:
break
return have_circle
G = [[0,1,0],[0,0,1],[1,0,0]] #這裏的1說明行index對應的節點指向列index對應的節點,對角線處爲0
# G = [[0,0,0,1,0],[1,0,0,0,0],[0,0,0,1,1],[0,0,0,0,0],[0,1,0,0,0]]
have_circle = findcircle(G)
print(have_circle)
2. 拓撲排序判斷環
拓撲排序方法是重複尋找一個入度爲0的頂點,將該頂點從圖中刪除(即放進一個隊列裏存着,這個隊列的順序就是最後的拓撲排序),並將該結點及其所有的出邊從圖中刪除(即該結點指向的結點的入度減1,因爲下面代碼中有入度的都爲1,所以直接賦值爲0 即可),最終若圖中全爲入度爲1的點,則這些點至少組成一個迴路,或者最後的隊列中節點個數不爲中的個數,也說明有環。
def findcircle(G):
node_set = set()
r = len(G)
have_in_zero = True
while have_in_zero:
have_in_zero = False
for i in range(r):
if i not in node_set and not any([row[i] for row in G]):
node_set.add(i)
G[i] = [0] * r
have_in_zero = True
break
return False if len(node_set)==r else True
G = [[0,1,0],[0,0,1],[1,0,0]]
# G = [[0,0,0,1,0],[1,0,0,0,0],[0,0,0,1,1],[0,0,0,0,0],[0,1,0,0,0]]
have_circle = findcircle(G)
print(have_circle)