【问题标题】:How to use Boost MST Algorithm on a complete Graph [closed]如何在完整图上使用 Boost MST 算法 [关闭]
【发布时间】:2021-07-22 03:05:36
【问题描述】:

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

非常感谢。

【问题讨论】:

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


【解决方案1】:

这是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

【讨论】:

  • 非常感谢。像这样的东西正是我想要的!
  • 我有一个问题,有什么方法可以更有效地实现这一目标?在我看来, add_edge 函数会消耗大量时间。我目前正在一个具有 40k 个顶点的完整图上运行它,我需要很长时间才能添加所有这些边。如果我将权重存储在向量中,我的代码会运行得更快。我可以用它来初始化图形吗?
  • 当然。 BGL 中的所有内容都是通用的。只需传递向量的属性映射而不是边缘权重。如果您分享更多代码(首先应该包含在问题中),我们可以(有)帮助(ed)
猜你喜欢
  • 2013-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多