如何在完整图上使用 Boost MST 算法

时间:2021-04-28 18:05:44

标签: c++ boost boost-graph minimum-spanning-tree

我对 BGL 很陌生。我有以下问题:我有一个非常大的完整图形和每个边的权重,需要评估最小生成树。 我想使用 Boost Graph Libraries 实现。我应该使用什么结构来表示我的完整图形,我将如何调用算法?此外,我想将生成的子图存储在某种图形结构中,以便之后可以对 MST 执行不同的操作。

非常感谢。

1 个答案:

答案 0 :(得分:0)

这是一个 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_maproot_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";

演示

Live On Coliru

#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, boost::no_property,
                            boost::property<boost::edge_weight_t, 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, 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);

    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

    prim_minimum_spanning_tree(g, parent.data(),
           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
相关问题