fucking-algorithm icon indicating copy to clipboard operation
fucking-algorithm copied to clipboard

Prim 最小生成树算法 :: labuladong的算法小抄

Open utterances-bot opened this issue 3 years ago • 10 comments

文章链接点这里:Prim 最小生成树算法

评论礼仪 见这里,违者直接拉黑。

utterances-bot avatar Jan 21 '22 08:01 utterances-bot

// 图中有 n 个节点 int n = graph.length;

这里的n不是节点数量,而是存在的边的数量。

feifeijin avatar Jan 21 '22 08:01 feifeijin

我错了,n就是节点数量。。。可我不知道如何删除评论

feifeijin avatar Jan 21 '22 08:01 feifeijin

1135 题「 最低成本联通所有城市」,Prim算法的python实现

import heapq
import collections
class Solution:
    # Kruscal并查集方式判定
    class UnionFind(object):
        def __init__(self, n):
            self.parent = list(range(n))

        def find(self, x):
            while self.parent[x] != x:
                self.parent[x] = self.parent[self.parent[x]]
                x = self.parent[x]
            return x

        def union(self, x1, x2):
            self.parent[self.find(x1)] = self.find(x2)

        def connected(self, x1, x2):
            return self.find(x1) == self.find(x2)

    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        # 连边权重换成了曼哈顿距离
        def manhattan_distance(p1, p2):
            return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])

        # 1.uf并查集解决方案
        n = len(points)
        # uf = Solution.UnionFind(n)
        # # 遍历构建点之间距离数组
        distances = []
        for i in range(n):
            for j in range(i, n):
                distances.append(
                    (i, j, manhattan_distance(points[i], points[j])))

        # distances = sorted(distances, key=lambda x: x[-1])

        # count = 0
        # for dist in distances:
        #     x, y, x_y_dist = dist
        #     if uf.connected(x, y):
        #         continue
        #     uf.union(x, y)
        #     count += x_y_dist
        # return count

        # 2.BFS方式
        def build_graph(connections):  # 构建图
            graph = collections.defaultdict(list)
            # 无向图就是双向图
            for conn in connections:
                u, v, weight = conn
                graph[u].append((u, v, weight))
                graph[v].append((v, u, weight))
            return graph

        def cut(s):
            for edge in graph[s]:
                _from, _to, weight = edge
                if in_mst[_to]:
                    continue
                heapq.heappush(pq, (weight, _from, _to))

        graph = build_graph(distances)
        pq = []
        # 记录MST中的节点
        in_mst = [False] * n
        # 记录最终结果
        weight_sum = 0
        in_mst[0] = True
        cut(0)

        while pq:
            weight, _from, _to = heapq.heappop(pq)
            if in_mst[_to]:
                continue
            weight_sum += weight
            in_mst[_to] = True
            cut(_to)
        return weight_sum

Alwin4Zhang avatar Mar 28 '22 08:03 Alwin4Zhang

东哥 什么时候能有c++版的答案呢? 因为没有太多代码基础,看你的代码在写出c++版的有些吃力...

ZackHongru avatar Jun 08 '22 15:06 ZackHongru

什么时候出个弗洛依德算法呢!!

deweicai23 avatar Jun 18 '22 01:06 deweicai23

@ZackHongru 算法用的标准库就那么几个,看多了就习惯了。另外可以在评论区看看有没有别人的 cpp 代码。

labuladong avatar Jun 23 '22 08:06 labuladong

“Prim 算法的时间复杂度也是可以优化的,但优化点在于优先级队列的实现上” 能优于O(ElogE)吗?网上好像都是从array优化成priorityqueue,好像没有更优化的了

JerryWuZiJie avatar Jun 27 '22 18:06 JerryWuZiJie

@JerryWuZiJie priorityqueue 也有不同的实现,有些实现可以直接修改队列中的元素,这样的优先级队列可以进一步降低时间复杂度。Java 标准库的优先级队列不可以。

labuladong avatar Jul 01 '22 13:07 labuladong

对Prim算法的个人理解

个人认为,对于Prim算法的理解,用教科书上的“加点”可以更好接受。设已被连入最小生成树的集合位MST,则每一次选取连接到MST中cost最小的点。因此优先队列里永远放的都是点和该点连接到MST需要的最小cost(其实也还是边的权值),然后随着算法的执行,每个点连接到MST的cost也会不断被更新(不断往优先级队列里插入更小的cost,原来的cost不会被删除)。这样想可以把Prim和Dijkstra完全类比,两个算法只有一行代码不同。

附1135和1584两题Python简洁Prim解法:

1135. 最低成本联通所有城市

class Solution:
    def minimumCost(self, n: int, connections: List[List[int]]) -> int:
        graph = [[] for _ in range(n)]
        for connection in connections:
            graph[connection[0] - 1].append((connection[2], connection[1] - 1))
            graph[connection[1] - 1].append((connection[2], connection[0] - 1))
        heap = [(0, 0)]
        mst = set()
        cost = 0
        while heap:
            cur = heapq.heappop(heap)
            if cur[1] not in mst:
                mst.add(cur[1])
                cost += cur[0]
                for vertex in graph[cur[1]]:
                    heapq.heappush(heap, vertex)
        if len(mst) == n:
            return cost
        return -1

1584. 连接所有点的最小费用

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        graph = [[] for _ in range(n)]
        for i in range(n - 1):
            for j in range(i + 1, n):
                graph[i].append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), j))
                graph[j].append((abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]), i))
        heap = [(0, 0)]
        mst = set()
        cost = 0
        while heap:
            cur = heapq.heappop(heap)
            if cur[1] not in mst:
                mst.add(cur[1])
                cost += cur[0]
                for vertex in graph[cur[1]]:
                    heapq.heappush(heap, vertex)
            if len(mst) == n:
                return cost

825344491 avatar Jul 25 '22 18:07 825344491

@825344491 👍

labuladong avatar Jul 27 '22 01:07 labuladong

cut({A, B, C}) = cut({A, B}) + cut({C}) - [cut({A,B}) ^cut({B}) ],这样才对吧,减去它俩的交集

amark1235 avatar Aug 28 '22 13:08 amark1235

cut({A, B, C}) = cut({A, B}) + cut({C}) - [cut({A,B}) ^cut({C}) ],这样才对吧,减去它俩的交集, 刚写错了

amark1235 avatar Aug 28 '22 13:08 amark1235