繁体   English   中英

具有多态顶点和边的 boost::adjancency_list

[英]boost::adjancency_list with polymorphic vertices and edges

我正在学习 BGL 并拼凑一个程序(来自各种相关的 StackOverflow 答案)来构建一个应该能够处理多态顶点和边的图形。 该图应该能够处理平行边(相同类型或不同类型)。 我想将dijkstra_shortest_paths从起始vertex_descriptor到: 1. 所有 Park 的; 2. 所有公园和城市的; 3. 仅限全市的铁路。 这甚至可能吗? 谢谢你。

#include <iostream>
#include <deque>

#include "boost/graph/adjacency_list.hpp"
#include "boost/graph/topological_sort.hpp"
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/variant.hpp>


#include <boost/graph/adj_list_serialize.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>

using namespace boost;

struct Highway {
  std::string name;
  int miles;
  int speed_limit;
  int lanes;
  bool divided;
};

struct Railway { 
  std::string name; 
  int km;
};

struct City {
  std::string name;
  int population;
  std::vector<int> zipcodes;
};

struct Park {
  std::string name;
  int population;
  std::vector<int> zipcodes;
};


struct Country {
  std::string name;
  bool use_right;   // Drive on the left or right
  bool use_metric;  // mph or km/h
};

int main(int argc, char *argv[]) {

  typedef boost::adjacency_list<
    boost::listS, boost::vecS, boost::bidirectionalS,
    boost::variant<City, Park>, boost::variant<Highway, Railway>, Country>
      Map;

  City c1 = {"San Jose", 1200000, {95126, 95128}};
  City c2 = {"San Francisco", 500000, {95008, 95009}};
  City c3 = {"Santa Cruz", 300000, {94001, 94002}};
  City c4 = {"Oakland", 800000, {93001, 93002}};
  City c5 = {"San Diego", 2800000, {92001, 92002}};

  Map map; // load the map
  Map::vertex_descriptor c1d = boost::add_vertex(c1, map),
    c2d = boost::add_vertex(c2, map),
    c3d = boost::add_vertex(c3, map),
    c4d = boost::add_vertex(c4, map), 
    c5d = boost::add_vertex(c5, map); 
  add_edge(c1d, c2d, Highway{"101", 42, 65, 3, true}, map);
  add_edge(c2d, c3d, Highway{"280", 52, 60, 1, true}, map);
  add_edge(c2d, c3d, Highway{"92", 13, 60, 1, true}, map);
  //add_edge(c2, c3, map);
  //add_edge(c1, c3, map);

  map[graph_bundle].name = "United States";
  map[graph_bundle].use_right = true;
  map[graph_bundle].use_metric = false;

  using vertex_descriptor = boost::graph_traits<Map>::vertex_descriptor;

  Map::vertex_descriptor from = *vertices(map).first;
  std::vector<int> distances(num_vertices(map));
  auto v_index = get(boost::vertex_index, map);
  auto v_bundle = get(boost::vertex_bundle, map);
  dijkstra_shortest_paths(map, from,
      weight_map(get(get(&Highway::miles, map))
      .distance_map(make_iterator_property_map(distances.begin(),
      get(vertex_index, map))));
  std::cout << "distances and parents:" << std::endl;
  graph_traits <Map>::vertex_iterator vi, vend;
  for (boost::tie(vi, vend) = vertices(map); vi != vend; ++vi) {
    std::cout << "distance(" << get<City>(&City::name, map[*vi]) << ") = " << distances[*vi] << ", " << "\n";
  }
  std::cout << std::endl;

  return 0;
}

因此,简而言之,您希望从变体元素类型访问属性。 您可以创建自己的属性 map,方便您自己的访问器集使用属性 map 适配器。

后者工作最少:

auto highway_miles = boost::make_transform_value_property_map(
    [](Interconnect const& conn) {
        if (auto* c = boost::get<Highway>(&conn)) {
            return c->miles;
        } else {
            return std::numeric_limits<Distance>::max();
        }
    },
    get(boost::edge_bundle, map));

dijkstra_shortest_paths(
    map, from,
    weight_map(highway_miles)
        .distance_map(make_iterator_property_map(
            distances.begin(), v_index)));

事实上,使用vecS选择的顶点容器选择器,您可以更简洁地编写它:

dijkstra_shortest_paths(
    map, from, weight_map(highway_miles).distance_map(distances.data()));

现场演示

实时编译器资源管理器

#include <deque>
#include <iostream>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/variant.hpp>

using Distance = int;

struct Highway {
    std::string name;
    Distance    miles;
    unsigned    speed_limit, lanes;
    bool        divided;
};

struct Railway {
    std::string name;
    Distance    km;
};

struct City {
    std::string           name;
    unsigned              population;
    std::vector<unsigned> zipcodes;
};

struct Park {
    std::string           name;
    unsigned              population;
    std::vector<unsigned> zipcodes;
};

using Interconnect = boost::variant<Highway, Railway>;
using Area = boost::variant<City, Park>;

enum class RoadOrientation { right, left };
enum class UnitSystem { metric, imperial };

struct Country {
    std::string     name;
    RoadOrientation driving;
    UnitSystem      measure;
};

using Map = boost::adjacency_list<                    //
    boost::listS, boost::vecS, boost::bidirectionalS, //
    Area, Interconnect, Country>;

int main()
{
    Map map;
    map[boost::graph_bundle] = {
        "United States",
        RoadOrientation::right,
        UnitSystem::imperial,
    };

    auto c1d = add_vertex(City{"San Jose",      1200000, {95126, 95128}}, map);
    auto c2d = add_vertex(City{"San Francisco", 500000,  {95008, 95009}}, map);
    auto c3d = add_vertex(City{"Santa Cruz",    300000,  {94001, 94002}}, map);
               add_vertex(City{"Oakland",       800000,  {93001, 93002}}, map);
               add_vertex(City{"San Diego",     2800000, {92001, 92002}}, map);

    add_edge(c1d, c2d, Highway{"101", 42, 65, 3, true}, map);
    add_edge(c2d, c3d, Highway{"280", 52, 60, 1, true}, map);
    add_edge(c2d, c3d, Highway{"92",  13, 60, 1, true}, map);

    using V = Map::vertex_descriptor;

    V                from = vertex(0, map);
    std::vector<int> distances(num_vertices(map));

    auto v_index       = get(boost::vertex_index, map);
    auto highway_miles = boost::make_transform_value_property_map(
        [](Interconnect const& conn) {
            if (auto* c = boost::get<Highway>(&conn)) {
                return c->miles;
            } else {
                return std::numeric_limits<Distance>::max();
            }
        },
        get(boost::edge_bundle, map));

    dijkstra_shortest_paths(
        map, from,
        weight_map(highway_miles)
            .distance_map(make_iterator_property_map(
                distances.begin(), v_index)));

    dijkstra_shortest_paths(
        map, from, weight_map(highway_miles).distance_map(distances.data()));

    std::cout << "distances and parents:" << std::endl;

    auto name_of = [](auto const& area) {
        return boost::apply_visitor(
            [](auto const& c_or_p) { return c_or_p.name; }, area);
    };

    for (auto v : boost::make_iterator_range(vertices(map)))
        std::cout << "distance(" << name_of(map[v]) << ") = " << distances[v] << "\n";
}

印刷

distances and parents:
distance(San Jose) = 0
distance(San Francisco) = 42
distance(Santa Cruz) = 55
distance(Oakland) = 2147483647
distance(San Diego) = 2147483647

更多创意

我过去曾提供过建议/替代方案:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM