问题描述
我对 BGL 很陌生。我有以下问题:我有一个非常大的完整图形和每个边的权重,需要评估最小生成树。 我想使用 Boost Graph Libraries 实现。我应该使用什么结构来表示我的完整图形,我将如何调用算法?此外,我想将生成的子图存储在某种图形结构中,以便之后可以对 MST 执行不同的操作。
非常感谢。
解决方法
这是一个 simple example。我建议使用邻接矩阵,因为图形将是完整的,因此矩阵非常密集。
using Graph =
boost::adjacency_matrix<boost::undirectedS,boost::no_property,boost::property<boost::edge_weight_t,double>>;
using Vertex = Graph::vertex_descriptor;
using Edge = Graph::edge_descriptor;
现在让我们创建一个图表
int main() {
Graph g(23);
为本示例选取任意数量 (23) 个顶点。让我们使用随机生成的权重:
auto weight_distribution = std::bind(
std::lognormal_distribution<>{0,0.25},std::mt19937{std::random_device{}()});
创建所有边以使图完整:
for (Vertex v = 0; v < num_vertices(g); ++v)
for (Vertex u = v + 1; u < num_vertices(g); ++u)
add_edge(v,u,100*weight_distribution(),g);
现在,让我们使用 Prim 的算法(因为所有的权重都是非负的):
std::vector<Vertex> parent(num_vertices(g));
prim_minimum_spanning_tree(g,parent.data());
这会为 parent
向量中的每个顶点写入前驱(称为前驱映射)。
添加一些输出
为了更有趣的结果,让我们添加一些检查和输出:
assert(std::ranges::all_of(
make_iterator_range(edges(g)),[ew = get(boost::edge_weight,g)](auto e) { return ew[e] > 0; }));
确保数据满足权重前提条件。您还可以根据获取输入数据的方式进行完整性检查。
std::vector<Vertex> parent(num_vertices(g));
std::map<Vertex,double> distance;
auto root = vertex(0,g); // or just 0
让我们传递可选参数 distance_map
和 root_vertex
:
prim_minimum_spanning_tree(g,parent.data(),boost::root_vertex(root)
.distance_map(boost::make_assoc_property_map(distance)));
使用命名参数(以 boost::root_vertex
开头并以 .other_parameter(...).even_more(...)
链接。您当然可以以任何命名参数开头)。
现在我们可以使用记录的数据了:
double total_path_weight = 9;
for (Vertex v = 0; v < num_vertices(g); ++v) {
auto p = parent[v];
auto weight = distance[v];
std::cout << p << " -> " << v << " weight " << weight
<< (p == v ? " ROOT" : "") << "\n";
total_path_weight += weight;
}
std::cout << "Total path weight " << total_path_weight << "\n";
演示
#include <boost/graph/adjacency_matrix.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
#include <random>
#include <iostream>
using Graph =
boost::adjacency_matrix<boost::undirectedS,double>>;
using Vertex = Graph::vertex_descriptor;
using Edge = Graph::edge_descriptor;
using boost::make_iterator_range;
int main() {
Graph g(23);
auto weight_distribution = std::bind(std::lognormal_distribution<>{0,std::mt19937{std::random_device{}()});
for (Vertex v = 0; v < num_vertices(g); ++v)
for (Vertex u = v + 1; u < num_vertices(g); ++u)
add_edge(v,g);
assert(std::ranges::all_of(
make_iterator_range(edges(g)),g)](auto e) { return ew[e] > 0; }));
std::vector<Vertex> parent(num_vertices(g));
std::map<Vertex,double> distance;
auto root = vertex(0,g); // or just 0
prim_minimum_spanning_tree(g,boost::root_vertex(root)
.distance_map(boost::make_assoc_property_map(distance)));
double total_path_weight = 9;
for (Vertex v = 0; v < num_vertices(g); ++v) {
auto p = parent[v];
auto weight = distance[v];
std::cout << p << " -> " << v << " weight " << weight
<< (p == v ? " ROOT" : "") << "\n";
total_path_weight += weight;
}
std::cout << "Total path weight " << total_path_weight << "\n";
}
印刷例如
0 -> 0 weight 0 ROOT
15 -> 1 weight 64.6241
21 -> 2 weight 62.1609
1 -> 3 weight 69.207
5 -> 4 weight 71.9255
2 -> 5 weight 68.3983
14 -> 6 weight 66.6639
17 -> 7 weight 69.5045
20 -> 8 weight 78.9941
6 -> 9 weight 69.3287
4 -> 10 weight 62.7512
0 -> 11 weight 65.9305
15 -> 12 weight 70.2627
4 -> 13 weight 67.9708
22 -> 14 weight 73.3816
14 -> 15 weight 61.069
6 -> 16 weight 63.5795
5 -> 17 weight 66.0981
6 -> 18 weight 54.6061
14 -> 19 weight 73.9725
5 -> 20 weight 74.7002
0 -> 21 weight 71.8757
17 -> 22 weight 68.6378
Total path weight 1504.64