Mind and Hand Help

Minimum Spanning Tree (Undirected)

最小生成树

具体实现

class Mst(graph: Graph) : GraphCompute(graph) { init { checkEmpty().checkDirected(false).checkWeighted(true) if (Components(graph).compute().componentCount > 1) { throw IllegalArgumentException("Graph is not connected, cannot compute MST") } } /** * Lazy Prim算法:懒惰删除 + 最小堆 + 切分 */ fun lazyPrim(): Result { val result = Result() val visited = BooleanArray(graph.getVertexesNum()) val start = graph.vertexIndex().getVertex(0)!! val minHeap = PriorityQueue<Edge>(compareBy { it.weight }) lazyPrim(start, visited, minHeap, result) return result } /** * Prim算法的递归实现:深度遍历 + 切分 */ private fun lazyPrim(vertex: Vertex, visited: BooleanArray, minHeap: PriorityQueue<Edge>, result: Result) { visited[vertex.id] = true minHeap.addAll(graph.adjacentEdges(vertex.id)) while (minHeap.isNotEmpty()) { val min = minHeap.poll()!! val toV = min.to if (!visited[toV.id]) { visited[toV.id] = true result.edges.add(min) result.totalWeight += min.weight // 形成切分,继续递归 lazyPrim(toV, visited, minHeap, result) } } } /** * Kruskal算法:最小堆 + 并查集 + 切分 */ fun kruskal(): Result { val result = Result() val vertexUF: UnionFind<Vertex> = IndexedUnionFind(Vertex::id) val edges = graph.getEdges() val queue = PriorityQueue<Edge>(compareBy { it.weight }) queue.addAll(edges) while (queue.isNotEmpty()) { val minE = queue.poll() val fromV = minE.from val toV = minE.to vertexUF.add(fromV) vertexUF.add(toV) if (!vertexUF.isConnected(fromV, toV)) { // 说明不在同一个集合中 result.edges.add(minE) result.totalWeight += minE.weight vertexUF.union(fromV, toV) } } return result } /** * MST计算结果 */ data class Result( val edges: MutableList<Edge> = mutableListOf(), var totalWeight: Double = 0.0 ) { /** * 获取边的数量 */ fun getEdgeCount(): Int = edges.size /** * 检查是否形成了连通的MST */ fun isConnected(vertexCount: Int): Boolean = edges.size == vertexCount - 1 /** * 获取所有边的权重列表 */ fun getWeights(): List<Double> = edges.map { it.weight } /** * 打印MST信息 */ fun printMst() { println("=== Minimum Spanning Tree ===") println("Total Weight: $totalWeight") println("Edge Count : ${edges.size}") println("Edges:") edges.forEachIndexed { index, edge -> println(" ${index + 1}. ${edge.from.name} -> ${edge.to.name}, weight: ${edge.weight}") } } override fun toString(): String { return "MST(edges=${edges.size}, totalWeight=$totalWeight)" } } }
27 January 2026