牛客-计算机复试题-求图的连通分支数

求图的连通分支数可以用并查集实现。
并查集的讲解推荐:
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))
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值