牛客-計算機複試題-求圖的連通分支數

求圖的連通分支數可以用並查集實現。
並查集的講解推薦:
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))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章