You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求Dijkstra最小生成树算法示例,已知其单源最短路径算法

Cycle-Breaking Algorithm for Minimum Spanning Trees (MST)

Hey there! First, let's clear up a key confusion: the algorithm you learned in class isn't related to Dijkstra's algorithm at all. Dijkstra's solves single-source shortest path problems, while what you're working with is a valid (but underdiscussed) method for building a Minimum Spanning Tree called the Cycle-Breaking Algorithm. That's likely why your searches came up empty—you were using the wrong keywords!

How the Algorithm Works (Recap + Clarification)

Your class description is spot-on. Here's the full, step-by-step breakdown:

  • Start with the entire graph (all nodes and all edges included—this will definitely have cycles)
  • Find any cycle in the graph, identify the edge with the largest weight in that cycle
  • Remove that heavy edge (since it's the most "unnecessary" edge keeping the cycle alive)
  • Repeat the process until there are no cycles left. What's left is your MST: a subgraph that connects all nodes, has no cycles, and has the smallest possible total edge weight.

This works because MSTs are defined as acyclic, fully connected subgraphs with minimal total weight. By stripping out the heaviest edges that cause cycles, we're left with the leanest possible connected graph.

Python Code Example

To implement this, we need two core tools:

  1. A way to detect cycles efficiently (we'll use the Union-Find/Disjoint Set Union (DSU) data structure)
  2. A way to find the heaviest edge in any cycle

Here's a practical implementation:

class UnionFind:
    def __init__(self, node_count):
        self.parent = list(range(node_count))
        self.rank = [0] * node_count

    def find(self, node):
        # Path compression for efficiency
        if self.parent[node] != node:
            self.parent[node] = self.find(self.parent[node])
        return self.parent[node]

    def union(self, node_a, node_b):
        # Union by rank to keep the tree shallow
        root_a = self.find(node_a)
        root_b = self.find(node_b)

        if root_a == root_b:
            # Nodes are already connected—adding this edge creates a cycle
            return False
        
        if self.rank[root_a] < self.rank[root_b]:
            self.parent[root_a] = root_b
        else:
            self.parent[root_b] = root_a
            if self.rank[root_a] == self.rank[root_b]:
                self.rank[root_a] += 1
        return True

def cycle_breaking_mst(edges, total_nodes):
    # Start with all edges included
    current_edges = edges.copy()

    while True:
        # Check if the current edge set has any cycles
        dsu = UnionFind(total_nodes)
        cycle_found = False
        heaviest_cycle_edge = None

        # Sort edges from heaviest to lightest to find the first one that creates a cycle
        for edge in sorted(current_edges, key=lambda x: -x[2]):
            u, v, weight = edge
            if not dsu.union(u, v):
                heaviest_cycle_edge = edge
                cycle_found = True
                break
        
        if not cycle_found:
            # No cycles left—we have our MST
            break
        
        # Remove the heaviest edge that's causing a cycle
        current_edges.remove(heaviest_cycle_edge)
    
    return current_edges

# Example usage
if __name__ == "__main__":
    # Edge format: (node_u, node_v, edge_weight) (nodes are 0-indexed)
    sample_edges = [
        (0, 1, 4),
        (0, 2, 1),
        (1, 2, 2),
        (1, 3, 5),
        (2, 3, 3)
    ]
    num_nodes = 4

    mst_result = cycle_breaking_mst(sample_edges, num_nodes)
    print("Minimum Spanning Tree Edges:")
    for edge in mst_result:
        print(f"Node {edge[0]} ↔ Node {edge[1]} (Weight: {edge[2]})")
    print(f"Total MST Weight: {sum(edge[2] for edge in mst_result)}")

Quick Notes on the Code

  • Union-Find (DSU) is used here to quickly check if adding an edge creates a cycle. It's far more efficient than naive cycle detection for larger graphs.
  • This implementation takes a shortcut: instead of hunting for arbitrary cycles, we check edges from heaviest to lightest. Any edge that creates a cycle when added is guaranteed to be the heaviest edge in some cycle, so removing it works perfectly for our goal.
  • The time complexity is similar to Kruskal's algorithm (O(E log E)) because we sort edges multiple times—this is efficient enough for most practical use cases.

Why You Didn't Find This Online

Most resources focus on Kruskal's (add light edges, avoid cycles) or Prim's (build MST node-by-node) algorithms because they're often more intuitive to teach and implement. The cycle-breaking method is essentially the reverse of Kruskal's—instead of building up the MST, we tear down the full graph by removing unnecessary heavy edges.


内容的提问来源于stack exchange,提问作者Marcus Kim

火山引擎 最新活动