CPP 提升访客多目标

CPP Boost Visitor Multi Target

我有以下问题。我想使用 boost 中的 DIJKSTRA 算法。此外,我想在命中某个目标节点时停止搜索。我的第一个实现适用于单个目标节点:

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( ... ) {}

有以下访问者:

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);
}

目前我只能处理单端节点 (vertex_descriptor targ)。我想更改我的代码,允许端节点向量。然后,如果达到 end_nodes 之一,访问者应该停止。 有人可以帮我修改吗? 每次我尝试将 targ 的类型更改为 vector 之类的东西时,我都会遇到访问者模板的问题?

此致, 克里斯

不是持有单个目标 Vertex 而是 target_visitor 持有 std::set<Vertex> 并检查顶点是否在该集合内。

我修改了 http://lists.boost.org/boost-users/2006/03/18043.php 中的代码来证明这一点:

#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;
}

假设您使用 boost::unordered_set 来存储您的顶点,您可以通过以下方式实现它:

template <class Vertex, class Tag>struct target_visitor : public default_dijkstra_visitor{
  target_visitor(unordered_set<Vertex> u) : v(u) { }
  template <class Graph>

  void examine_vertex(Vertex u, Graph& g)
  {
    if( v.find(u) != v.end() ) {
      throw(-1);
    }
  }
private:
  unordered_set<Vertex> v;
};

template <class Vertex, class Tag>
target_visitor<Vertex, Tag>target_visit(unordered_set<Vertex> u, Tag) {
  return target_visitor<Vertex, Tag>(u);
}

然后你给访客打电话:

vertex_descriptor src = vertex(start_vertex, g); //start_node
unordered_set<vertex_descriptor> targets;

targets.insert(vertex(end_vertex1, g));
targets.insert(vertex(end_vertex2, g));

try {
    dijkstra_shortest_paths(g, src,predecessor_map(&p[0])
     .distance_map(&d[0])
     .visitor(target_visit(targets, on_examine_vertex())));
} catch( ... ) {}