zoukankan      html  css  js  c++  java
  • 算法89---图的最小生成树

    一、Prim算法实现

    思路:

    1、一个存储最小树的边列表mst、一个存储最小树的点集合used、一个堆,排序最小树边缘的最小边。堆顶为最小值。

    2、建立邻接表,如{'A':[(7,'A','B'),(5,'A','D')]}

    3、随机选初始点

    4、排序初始点的边权重,建立堆

    代码:

    from heapq import heapify, heappop, heappush
    from collections import defaultdict
    
    
    def prim(nodes, edges):
        #######conn是邻接表,字典形式
        conn = defaultdict(list)
        ####建立邻接表,如{'A':[(7,'A','B'),(5,'A','D')]}
        for n1, n2, c in edges:
            conn[n1].append((c, n1, n2))
            conn[n2].append((c, n2, n1))
    
        ##### mst就是存边结果,[('A','D',5)……]
        mst = []
        ##### used就是存已经放进mst中的点,
        used = set(nodes[0])
        ##### usable_edges 为建立好的树(采用堆排序建立的树)
        usable_edges = conn[nodes[0]][:]
        #####堆排序,保证堆顶的边权重为最小。
        heapify(usable_edges)
    
        ##### 堆中弹出的点为最后加入的点,其连接的其他边如果不在used里,则加入堆中
        while usable_edges:
            cost, n1, n2 = heappop(usable_edges)
            if n2 not in used:
                used.add(n2)
                mst.append((n1, n2, cost))
                ####conn最后加入的点的其他边的也加入堆中
                for e in conn[n2]:
                    if e[2] not in used:
                        heappush(usable_edges, e)
        return mst
    
    
    nodes = list("ABCDEFG")
    edges = [("A", "B", 7), ("A", "D", 5),
             ("B", "C", 8), ("B", "D", 9),
             ("B", "E", 7), ("C", "E", 5),
             ("D", "E", 15), ("D", "F", 6),
             ("E", "F", 8), ("E", "G", 9),
             ("F", "G", 11)]
    print ("prim:", prim(nodes, edges))

    二、村庄造路问题:

    题目:已知m个奇、偶数为0或1,arr(i,j)为i到j的代价,则需要知道所有数的最小代价是多少?

    如:

    input:m = 4, arr = [[2,1,3],[2,1],[3]]

    output:最小代价 = 4

    ############################

    思路:图的最小生成树 ,新建一个起始点,然后建立无向图,找到最小生成树,输出最小生成树的价值和即可。

    代码:

     

    from collections import defaultdict
    from heapq import heapify, heappush, heappop
    import sys
    
    
    def prim(m, arr):
        if len(arr) == 0 or len(arr[0]) == 0:
            return 0
        nodes = [i for i in range(m)]
        graph = defaultdict(list)
        res = 0
        for i in range(len(arr)):
            for j in range(1,len(arr[i])):
                graph[i].append([arr[i][j], i, i + j + 1])
    
        use_node = set([nodes[0]])
        heap_node = graph[0]
        heapify(heap_node)
        while heap_node:
            val, u, v = heappop(heap_node)
            if v not in use_node:
                use_node.add(v)
                res += val
                for e in graph[v]:
                    if e[2] not in use_node:
                        heappush(heap_node, e)
        return res
    
    
    m = 3
    arr = [[2, 1, 3], [2, 1], [3]]
    # arr = [[1,2,2],[1,2],[1]]
    print(prim(m, arr))

    三、360春招2019笔试题——三角形优化

    题目:

    题目:已知m个奇、偶数为0或1,arr(i,j)为i到j的代价,则需要知道所有数的最小代价是多少?
    如:
    input:m = 4,
    arr = [[2,1,3],[2,1],[3]]
    output:最小代价 = 4

    思路:

    图的最小生成树 把除了每一行的第一个数,用别的值建立无向图,找到最小生成树,再加上每一行第一个数的最小值即可。

    代码:

    from collections import defaultdict
    from heapq import heapify, heappush, heappop
    import sys
    
    
    def prim(m, arr):
        if len(arr) == 0 or len(arr[0]) == 0:
            return 0
        nodes = [i for i in range(m)]
        graph = defaultdict(list)
        res = 0
        for i in range(len(arr)):
            for j in range(1,len(arr[i])):
                graph[i].append([arr[i][j], i, i + j + 1])
    
        use_node = set([nodes[0]])
        heap_node = graph[0]
        heapify(heap_node)
        while heap_node:
            val, u, v = heappop(heap_node)
            if v not in use_node:
                use_node.add(v)
                res += val
                for e in graph[v]:
                    if e[2] not in use_node:
                        heappush(heap_node, e)
        return res
    
    
    m = 3
    arr = [[2, 1, 3], [2, 1], [3]]
    # arr = [[1,2,2],[1,2],[1]]
    print(prim(m, arr))

    四、克鲁斯卡尔算法

    代码:

    class DisjointSet(dict):
        '''不相交集'''
    
        def __init__(self, dict):
            pass
    
        def add(self, item):
            self[item] = item
    
        def find(self, item):
            if self[item] != item:
                self[item] = self.find(self[item])
            return self[item]
    
        def unionset(self, item1, item2):
            self[item2] = self[item1]
    
    
    def Kruskal_1(nodes, edges):
        '''基于不相交集实现Kruskal算法'''
        forest = DisjointSet(nodes)
        MST = []
        for item in nodes:
            print(item)
            forest.add(item)
        edges = sorted(edges, key=lambda element: element[2])
        num_sides = len(nodes)-1  # 最小生成树的边数等于顶点数减一
        for e in edges:
            node1, node2, _ = e
            parent1 = forest.find(node1)
            parent2 = forest.find(node2)
            if parent1 != parent2:
                MST.append(e)
                num_sides -= 1
                if num_sides == 0:
                    return MST
                else:
                    forest.unionset(parent1, parent2)
        pass
    
    
    def Kruskal(nodes, edges):
        ''' Kruskal 无向图生成最小生成树 '''
        all_nodes = nodes  # set(nodes)
        used_nodes = set()
        MST = []
        edges = sorted(edges, key=lambda element: element[2], reverse=True)
        # 对所有的边按权重升序排列
        while used_nodes != all_nodes and edges:
            element = edges.pop(-1)
            if element[0] in used_nodes and element[1] in used_nodes:
                continue
            MST.append(element)
            used_nodes.update(element[:2])
            # print(used_nodes)
        return MST
    
    
    def main():
        nodes = set(list('ABCDEFGHI'))
        edges = [("A", "B", 4), ("A", "H", 8),
                 ("B", "C", 8), ("B", "H", 11),
                 ("C", "D", 7), ("C", "F", 4),
                 ("C", "I", 2), ("D", "E", 9),
                 ("D", "F", 14), ("E", "F", 10),
                 ("F", "G", 2), ("G", "H", 1),
                 ("G", "I", 6), ("H", "I", 7)]
        print("The undirected graph is :", edges)
        print("The minimum spanning tree by Kruskal is : ")
        print(Kruskal_1(nodes, edges))
    
    
    if __name__ == '__main__':
        main()
  • 相关阅读:
    Operation Queue
    Dispatch Sources
    Base64编码详解
    属性存取、直接访问实例变量
    管理关联对象和NSDictionary区别
    3个Block替换Delegate的场景
    Objective-C消息机制
    Dispatch Queues调度队列
    DNS64/NAT64 Networks(解决IPv6审核被拒)
    NSObject的Initialize与Load方法
  • 原文地址:https://www.cnblogs.com/Lee-yl/p/10503349.html
Copyright © 2011-2022 走看看