Search code examples
c++boostdijkstravisitor-pattern

CPP Boost Visitor Multi Target


I have the following problem. I would like to use the DIJKSTRA algorithm from boost. Furthermore, I would like to stop the search when I hit a certain target node. My first implementation works fine for a single target node:

vertex_descriptor src = vertex(start_vertex, g); //start_node
vertex_descriptor targ = vertex(end_vertex, g); //end_node
try {
dijkstra_shortest_paths(g, src,predecessor_map(&p[0]).distance_map(&d[0]).visitor(target_visit(targ,on_examine_vertex())));
}
catch( ... ) {}

with following visitor:

template <class Vertex, class Tag>struct target_visitor : public default_dijkstra_visitor{
target_visitor(Vertex u) : v(u) { }
template <class Graph>
void examine_vertex(Vertex u, Graph& g)
{
    if( u == v ) {
        throw(-1);
    }
}
private:
    Vertex v;
};
template <class Vertex, class Tag>
target_visitor<Vertex, Tag>target_visit(Vertex u, Tag) {
return target_visitor<Vertex, Tag>(u);
}

At the moment I can only treat single end nodes (vertex_descriptor targ). I would like to change my code that a vector of end nodes is allowed. Then the visitor should stop if one of the end_nodes is reached. Can someone help me to modify this? Everytime I tried to change the type of targ into something like vector I get a problem with the vistor template?

Regards, Chris


Solution

  • Instead of holding a single target Vertex make target_visitor hold a std::set<Vertex> and check if the Vertex is within that set.

    I modified the code from http://lists.boost.org/boost-users/2006/03/18043.php to demonstrate this:

    #include <iostream>
    
    #include <boost/graph/graph_traits.hpp>
    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/dijkstra_shortest_paths.hpp>
    
    #include <set>
    
    using namespace boost;
    
    template <class Vertex, class Tag>
    struct target_visitor : public default_dijkstra_visitor
    {
        target_visitor(const std::set<Vertex>& targets) : targets(targets) { }
    
        template <class Graph>
        void examine_vertex(Vertex v, Graph& g)
        {
            if(targets.find(v) != targets.end())
            {
                std::cout << "found target: " << v << std::endl;
                throw(-1);
            }
        }
    private:
        std::set<Vertex> targets;
    };
    
    template <class Vertex, class Tag>
    target_visitor<Vertex, Tag>
    target_visit(const std::set<Vertex>& targets, Tag)
    {
        return target_visitor<Vertex, Tag>(targets);
    }
    
    
    int main(int argc, char** argv)
    {
        typedef adjacency_list < listS, vecS, directedS,
                no_property, property < edge_weight_t, int > > graph_t;
        typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
        typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
        typedef std::pair<int, int> Edge;
    
        const int num_nodes = 5;
        enum nodes { A, B, C, D, E };
        char name[] = "ABCDE";
        Edge edge_array[] =
        {
            Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E),
            Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B)
        };
        int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 };
        int num_arcs = sizeof(edge_array) / sizeof(Edge);
    
        graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes);
        property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
    
        std::vector<vertex_descriptor> p(num_vertices(g));
        std::vector<int> d(num_vertices(g));
    
        vertex_descriptor src = vertex(A, g);
        std::set<vertex_descriptor> targets = {vertex(E, g), vertex(D, g)};
    
        try {
        dijkstra_shortest_paths(g, src,
                                predecessor_map(&p[0]).distance_map(&d[0]).visitor(target_visit(targets,
                                                                                                on_examine_vertex())));
        }
        catch( ... ) {
        }
    
        std::cout << "distances and parents:" << std::endl;
        graph_traits < graph_t >::vertex_iterator vi, vend;
        for (tie(vi, vend) = vertices(g); vi != vend; ++vi)
        {
            std::cout << "distance(" << name[*vi] << ") = " << d[*vi] << ", ";
            std::cout << "parent(" << name[*vi] << ") = " << name[p[*vi]] << std::endl; 
        }
        return 0;
    }