| 75 | } |
| 76 | |
| 77 | SpanningTree ComputeSpanningTreeInternal( |
| 78 | int num_nodes, |
| 79 | const std::vector<std::pair<int, int>>& edges, |
| 80 | const std::vector<float>& weights, |
| 81 | int root, |
| 82 | bool maximize) { |
| 83 | SpanningTree tree; |
| 84 | if (num_nodes <= 0) { |
| 85 | return tree; |
| 86 | } |
| 87 | |
| 88 | // For maximum spanning tree, we negate weights and find minimum. |
| 89 | float max_weight = 0; |
| 90 | if (maximize) { |
| 91 | for (const float w : weights) { |
| 92 | max_weight = std::max(max_weight, w); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // Build boost graph. |
| 97 | BoostGraph graph(num_nodes); |
| 98 | auto weight_map = boost::get(boost::edge_weight, graph); |
| 99 | |
| 100 | for (size_t i = 0; i < edges.size(); ++i) { |
| 101 | const auto& edge = edges[i]; |
| 102 | const float weight = maximize ? (max_weight - weights[i]) : weights[i]; |
| 103 | auto [e, inserted] = boost::add_edge(edge.first, edge.second, graph); |
| 104 | if (inserted) { |
| 105 | weight_map[e] = weight; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | // Run Kruskal's algorithm. |
| 110 | std::vector<EdgeDescriptor> mst_edges; |
| 111 | boost::kruskal_minimum_spanning_tree(graph, std::back_inserter(mst_edges)); |
| 112 | |
| 113 | // Convert MST edges to adjacency list. |
| 114 | std::vector<std::vector<int>> adjacency_list(num_nodes); |
| 115 | for (const auto& edge : mst_edges) { |
| 116 | const int source = static_cast<int>(boost::source(edge, graph)); |
| 117 | const int target = static_cast<int>(boost::target(edge, graph)); |
| 118 | adjacency_list[source].push_back(target); |
| 119 | adjacency_list[target].push_back(source); |
| 120 | } |
| 121 | |
| 122 | // Build parent pointers via BFS from specified root. |
| 123 | tree.root = root; |
| 124 | BuildParentsFromAdjacencyList(adjacency_list, tree.root, tree.parents); |
| 125 | |
| 126 | return tree; |
| 127 | } |
| 128 | |
| 129 | } // namespace |
| 130 |
no test coverage detected