求图的连通分支数可以用并查集实现。
并查集的讲解推荐:
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))