dfs判断
首先明确三个概念,未访问的节点记为白节点,正在访问但没访问完(说白了,就是一条路没走到头还没退递归栈)的为灰节点,已经访问完的退出递归栈的为黑节点。
有了这个概念,思路就很简单了,如果访问过程中遇到了灰节点说明指向祖先了,则存在环,不明白的动手画一画,或者等过两天我的修改。
话不多说,见代码:
邻接表版本:
# 首先根据题意建,示例图(邻接表表示法)
graph = {
'A': ['B'],
'B': ['C'],
'C': ['A'], # 这里形成了一个环
'D': ['E'],
'E': []
}
dfs判断过程:
def dfs(node):
if state[node] == 1:
return True
if state[node] == 2:
return False
state[node] = 1 #即将进入递归栈染灰
for neighbor in graph[node]:
if dfs(neighbor):
return True #部分有就都有
state[node] = 2 #路走完了,退栈,染黑
return False
全过程:
def has_cycle(graph):
state = {node: 0 for node in graph} #white: 0, gray: 1, black: 2
def dfs(node):
if state[node] == 1:
return True
if state[node] == 2:
return False
state[node] = 1 #即将进入递归栈染灰
for neighbor in graph[node]:
if dfs(neighbor):
return True #部分有就都有
state[node] = 2 #路走完了,退栈,染黑
return False
for v in graph:
if state[v] == 0:
if dfs(v):
return True
return False
有向图按上述处理就好了,无向图,加个父节点不访问,以免误判即可:
def has_cycle(graph):
state = {node: 0 for node in graph} #white: 0, gray: 1, black: 2
def dfs(node, parent):
if state[node] == 1:
return True
if state[node] == 2:
return False
state[node] = 1 #即将进入递归栈染灰
for neighbor in graph[node]:
if neighbor != parent: # 不访问父节点
if dfs(neighbor, node):
return True #部分有就都有
state[node] = 2 #路走完了,退栈,染黑
return False
for v in graph:
if state[v] == 0:
if dfs(v, -1):
return True
return False
至于邻接矩阵的,可以选择转化为邻接表;当然不转也可以,详情见下面代码,由于大同小异给出了无向图的,有向图的就少个父节点而已:
graph = [
[0, 1, 1, 0], # A
[1, 0, 0, 1], # B
[1, 0, 0, 1], # C
[0, 1, 1, 0] # D
]
def has_cycle(graph):
n = len(graph)
state = [0]*n
def dfs(node, parent):
if state[node] == 1:
return True
if state[node] == 2:
return False
state[node] = 1 #即将进入递归栈染灰
for neighbor in range(n):
if neighbor != parent and graph[node][neighbor] == 1:
if dfs(neighbor, node):
return True #部分有就都有
state[node] = 2 #路走完了,退栈,染黑
return False
for v in graph:
if state[v] == 0:
if dfs(v, -1):
return True
return False
树的判断:
思路:连通分量为1(连通性),没有环的情况,就是树,所以在以上代码的情况上,添加一步连通分量的判断即可:
count = 0
for v in graph:
if state[v] == 0:
count += 1
if dfs(v, -1):
return False #有环,不是树
return count == 1 # 无环,检查连通性
其他:
连通分量不为1,拓扑排序(有向图)都可以判断图里是否含环,日后闲暇再整理。