使用labeled_graph提高图bellman_ford_shortest_paths

时间:2019-01-05 03:56:45

标签: c++ boost boost-graph

我正在尝试使用Boost库运行Bellman-Ford算法。我有一个带标签的图形,但是出现异常invalid conversion from ‘void*’ to ‘int。任何帮助将不胜感激。这是我的代码:

// g++ -std=c++17 -Wall test.c++ -l boost_system && ./a.out 

#include <iostream>                  // for cout
#include <utility>                   // for pair
#include <algorithm>                 // for for_each
#include <vector>                    // For dist[] and pred[]
#include <limits>                    // To reliably indicate infinity
#include <map>
#include <list>

#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/labeled_graph.hpp>
#include <boost/graph/bellman_ford_shortest_paths.hpp>

using namespace boost;
using namespace std;

class Node
{
  public:
    int id;
    int group;
};

struct EdgeProperties {
  double weight;

  EdgeProperties(){}
  EdgeProperties(double w){ weight = w; }
};

typedef labeled_graph<adjacency_list<hash_setS, hash_setS, directedS, Node, EdgeProperties>, int> Graph;

int main(){

    cout << "Calling main()" << endl;

    Graph g;

    // populate the graph
    {
        add_vertex( 0, g );
        g[0].id  = 0;
        g[0].group = 10;
        add_vertex( 1, g );
        g[1].id  = 1;
        g[1].group = 20;
        add_edge_by_label( 0, 1, EdgeProperties(110), g);
        add_edge_by_label( 1, 0, EdgeProperties(222), g);
        print_graph(g, get(&Node::id, g));
        cout << "There are " << num_vertices(g) << " nodes and " << num_edges(g) << " edges in the graph" << endl;
    }

    // number of verticies in the graph
    auto n = num_vertices(g);

    // weight map
    auto ewp = weight_map(get(&EdgeProperties::weight, g.graph()));

    const int source = 0;
    const int target = 1;

    // Distance Map (with n elements of value infinity; source's value is 0)
    auto inf = numeric_limits<double>::max();
    vector<double> dist(n, inf);
    dist[source] = 0.0;

    // Predecessor Map (with n elements)
    vector<int> pred(n);

    bellman_ford_shortest_paths(
        g.graph(), 
        n, 
        ewp
            .distance_map(make_iterator_property_map(dist.begin(), get(&Node::id, g)))
            .predecessor_map(make_iterator_property_map(pred.begin(), get(&Node::id, g)))
    );

    return 0;
}

我在https://www.boost.org/doc/libs/1_53_0/libs/graph/example/bellman-example.cpp上看到了该示例,但是该示例未使用标签图。

这是我的代码的实时预览:

https://wandbox.org/permlink/WsQA8A0IyRvGWTIj

谢谢

1 个答案:

答案 0 :(得分:1)

您接受的现有答案中已经提到了问题的根源。

但是,还有更多内容。

首先,您几乎是在“力所能及的范围内”想要使用Node::id作为顶点索引,并且可能有很多充分的理由将vector以外的东西用作顶点容器选择器¹。

第二,这些东西应该……可能已经起作用了。 bellman_ford documents

  

PredecessorMap类型必须是“读/写属性映射”,其键和顶点类型必须与图的顶点描述符类型相同。

还有iterator_property_map documents

  

此属性映射是将任何随机访问迭代器转换为Lvalue属性映射的适配器。 OffsetMap类型负责将键对象转换为可以用作随机访问迭代器的偏移量的整数。

现在LValuePropertyMap 可能实际上是只读的,但在这种情况下显然不应该是只读的。

在将make_iterator_property_map与附加的id-map参数一起使用时,实际上应该像算法要求的那样,具有键和值类型vertex_descriptor的任何关联属性映射。

  

更新请参见下面的“奖励”

稍后我可能会详细介绍一下为什么不起作用,但是现在让我们解决该问题而不修改图形模型:

Live On Coliru

auto gg = g.graph();
auto id = get(&Node::id, gg);
std::map<Graph::vertex_descriptor, Graph::vertex_descriptor> assoc_pred;

bellman_ford_shortest_paths(gg, n,
    weight_map(get(&EdgeProperties::weight, gg))
    .distance_map(make_iterator_property_map(dist.begin(), id))
    .predecessor_map(make_assoc_property_map(assoc_pred))
    );

这可以按预期工作:

Calling main()
1 --> 0 
0 --> 1 
There are 2 nodes and 2 edges in the graph

奖金

我找到了丢失的链接:先前的映射定义了错误的值类型:

vector<Graph::vertex_descriptor> pred(n);

显然可以正常工作: Live On Coliru


¹与顶点描述符略有不同,但在某种意义上相关,即选择顶点容器通常可以预测顶点描述符的实际类型