求圖的連通分支數可以用並查集實現。
並查集的講解推薦:
https://blog.csdn.net/liujian20150808/article/details/50848646
本題求的是無向圖的連通分支數,用Python代碼實現如下:
"""
無向或有向圖的連通分治數可以用並查集求出來。
並查集的本質是將圖分成多棵樹,每棵樹是每個連通分支的樹形表示,因此樹的總數等於連通分支的總數
並查集需要O(n)的空間,以記錄每個結點對應的父結點,其中n爲圖中結點的總數
我們設置了一個字典father來記錄每個結點的父結點,這裏不建議用列表記錄,字典更靈活
一開始需要對father進行初始化,建議對於每個結點n,一開始令father[n]=n
這樣最後算法結束後,如果一個結點rt,滿足father[rt]=rt,那就表明rt是其所在樹的根
顯然,從father中根的數目,就是連通分支的數量
並查集有兩大部分:
find_root(node): 找到node所在的樹的根節點
unite(node1, node2): 將node1, node2所在的樹合併
"""
class Graph(object):
"""
圖的構造可以用Python第三方庫,但我忘了叫什麼了,索性自己先簡單實現一下
"""
def __init__(self, *args, **kwargs):
""""
nodes: nodes記錄圖中的結點,a set
edges: edges記錄圖中的無向邊, a list of tuple
nodeNumber: 圖中結點數
edgeNumber: 圖中邊數
connectedComponents: 圖的連通分支數
"""
self.nodes = set([])
self.egdes = []
self.nodeNumber = 0
self.edgeNumber = 0
self.connectedComponents = 0
def addNode(self, node):
"""
添加結點node
:param node: 待添加結點
"""
self.nodes.add(node)
self.nodeNumber += 1
def addEdge(self, node1, node2):
"""
添加無向邊(node1, node2)
:param node1: 邊的一端
:param node2: 邊的一端
"""
self.egdes.append((node1, node2))
self.edgeNumber += 1
def getNodes(self):
"""
獲取graph當前的結點
:return: graph.nodes, a list
"""
return list(self.nodes)
def getEdges(self):
"""
獲取graph當前的邊
:return: graph.edges, a list
"""
return self.egdes
def find_root(node):
"""
找到結點node的根
這裏使用到了路徑壓縮,縮短查找時間
還有其他減少縮短查找時間的方法,這裏用了比較簡單的一種
"""
son = node
while father[node] != node:
node = father[node]
''' 路徑壓縮 '''
while son != node:
tmp = father[son]
father[son] = node
son = tmp
return node
def unite(x, y):
"""
將x, y所在的樹合併。
利用find_root找到x, y所在樹的根結點fx, fy
如果fx==fy,說明x, y在同一棵樹
否則,說明x, y不在同一棵樹,對兩棵樹進行合併 (令father[fx]=fy或father[fy]=fx)
"""
fx, fy = find_root(x), find_root(y)
if fx != fy:
father[fx] = fy
def cal_connected_compnt(graph):
"""
求出graph的連通分支數
:param graph: 待處理的圖
:return: 圖的連通分支數
"""
edges, edgesNumber = graph.getEdges(), graph.edgeNumber
for u, v in edges:
unite(u, v)
for key, value in father.items():
if key == value:
graph.connectedComponents += 1
return graph.connectedComponents
if __name__ == '__main__':
graph = Graph()
while True:
try:
inputLine = [int(_) for _ in input().strip().split()]
u, v = inputLine[0], inputLine[1]
graph.addNode(u)
graph.addNode(v)
graph.addEdge(u, v)
except:
break
father = {number: number for number in graph.getNodes()}
print(cal_connected_compnt(graph))