Boost dijkstra string edge weight

孤街醉人 提交于 2019-12-12 18:43:53

问题


is it possible to use string value instead of double properties typedef adjacency_list < vecS, vecS, directedS, property<vertex_name_t, string>, property < edge_weight_t, string> > Graph; My goal is to use the dijkstra algorithm. PS: I already tried replacing the double with string and it generates an error within the algorithm.

std::vector<vertexd> P(num_vertices(g));
std::vector<string> d(num_vertices(g));
vertexd s = vertex(0, g);

dijkstra_shortest_paths(g, s,
    predecessor_map(boost::make_iterator_property_map(P.begin(), get(boost::vertex_index, g))).
    distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, g))));

Error:

Error 13 error C2664: 'D boost::closed_plus::operator ()(const T &,const T &) const' : cannot convert argument 2 from 'const std::basic_string,std::allocator>' to 'const D &' C:\boost_1_58_0\boost\graph\dijkstra_shortest_paths.hpp 190


回答1:


Yes you can have a string property.

No, dijkstra requires

a weighted, directed or undirected graph for the case where all edge weights are nonnegative

So the weight is required to be numerical. Of course, if you can implement arithmetic operations and std::numeric_limit<> for your property type it might be fine (but you really have to scratch your head before doing that).

UPDATE _Actually, it turns out this documentation simplifies a bit, and you can actually override zero, comparison and combining for your weight type. See the linked sample in the comments (HT @cv_and_he)_

So, I hate to be that guy, but: why.

Since the weights are amounts in any unit anyways, what is the goal storing them as strings? Are you, perhaps having a different issue that prevents you from storing the weights properly?


That said, here's a way:

Using transform_value_property_map you can transform strings to doubles on the fly:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dag_shortest_paths.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>

using Weight = std::string;
//using Weight = double;

typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
        boost::property<boost::vertex_name_t, std::string>,
        boost::property<boost::edge_weight_t, Weight>
    > Graph;

using vertexd = Graph::vertex_descriptor;

Graph generate();

int main() {
    using namespace boost;

    Graph g = generate();
    std::vector<vertexd> P(num_vertices(g));
    std::vector<double>  d(num_vertices(g));
    vertexd s = vertex(0, g);

    auto to_double = [](Weight const& v) { return lexical_cast<double>(v); };

    dijkstra_shortest_paths(
        g, s, 
         weight_map  (make_transform_value_property_map(to_double, get(edge_weight, g)))
        .predecessor_map(make_container_vertex_map(P))
        .distance_map(make_container_vertex_map(d))
    );

    boost::dynamic_properties dp;
    dp.property("node_id", get(vertex_name, g));
    dp.property("label",  get(edge_weight, g));
    write_graphviz_dp(std::cout, g, dp);
}

#include <boost/graph/random.hpp>
#include <boost/range/iterator_range.hpp>
#include <random>

Graph generate() {
    using namespace boost;

    std::mt19937 prng { std::random_device {} () };
    Graph g;
    generate_random_graph(g, 10, 20, prng);

    for (auto v : make_iterator_range(vertices(g)))
        put(vertex_name, g, v, "vertex" + std::to_string(v));

#if 0
    // in case `Weight` is double
    auto gen_weight = [&, dist=std::uniform_real_distribution<Weight>(0,1)] () mutable -> Weight {
        return dist(prng);
    };
#else
    // in case `Weight` is std::string
    auto randchar = [&, dist=std::uniform_int_distribution<>('0','9')] () mutable -> char { return dist(prng); };

    auto gen_weight = [&] () {
        Weight tmp(3, ' ');
        std::generate(tmp.begin(), tmp.end(), randchar);
        return tmp;
    };
#endif

    for (auto e : make_iterator_range(edges(g)))
        put(edge_weight, g, e, gen_weight());

    return g;
}

Outputs the graph randomly generated, e.g.:

digraph G {
    vertex0->vertex5  [label=503];
    vertex0->vertex8  [label=653];
    vertex0->vertex8  [label=931];
    vertex1->vertex6  [label=022];
    vertex1->vertex8  [label=536];
    vertex1->vertex5  [label=400];
    vertex1->vertex4  [label=056];
    vertex3->vertex8  [label=555];
    vertex4->vertex7  [label=052];
    vertex4->vertex6  [label=542];
    vertex4->vertex3  [label=024];
    vertex5->vertex7  [label=595];
    vertex5->vertex8  [label=850];
    vertex7->vertex4  [label=464];
    vertex7->vertex9  [label=484];
    vertex8->vertex0  [label=274];
    vertex8->vertex1  [label=131];
    vertex8->vertex6  [label=529];
    vertex9->vertex1  [label=239];
    vertex9->vertex3  [label=362];
}

Which is rendered as



来源:https://stackoverflow.com/questions/34878147/boost-dijkstra-string-edge-weight

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!