代码之家  ›  专栏  ›  技术社区  ›  Etan bbum

仅传递一个STD::向量属性到BGL算法

  •  0
  • Etan bbum  · 技术社区  · 14 年前

    我有一个带有多个边权重的图形存储为

    namespace boost {
        enum edge_weightvector_t {
            edge_weightvector = 1337
        };
        BOOST_INSTALL_PROPERTY(edge, weightvector);
    }
    
    typedef boost::adjacency_list<
        boost::vecS,
        boost::vecS,
        boost::undirectedS,
        boost::no_property,
        boost::property<boost::edge_weightvector_t, std::vector<int> >
    > graph_t;
    

    权重都被推到向量上。

    现在我想打电话给 prim_minimum_spanning_tree() 函数,向量中的第一个元素用作权重。

    如何执行正确的函数调用?

    2 回复  |  直到 10 年前
        1
  •  0
  •   Etan bbum    14 年前

    我现在已经做到了,首先将所需的权重复制到一个附加属性,然后运行算法,然后再复制回来。它很难看,但在我的例子中它起到了作用。

        2
  •  0
  •   normanius    10 年前

    我最近也尝试了同样的方法(使用向量属性),但没有用其中一个值运行算法。但是,我发现使用 exterior properties 是一种很好的方法,它不会导致不必要的复制操作,并将属性映射显式传递给算法。

    如果使用随机访问容器,则可以使用 boost::iterator_property_map 那会把那个容器包装起来 property_map . 它不需要边缘描述符,而是需要基于0的边缘索引,以便在边缘和属性值之间进行有效映射。下面是punchline,您将找到完整的示例:

    // ... 
    EdgeIndexMap edgeIds = get(edge_index, g);
    // ...
    typedef std::vector<int> Weights;
    typedef std::vector<Weights> WeightsVector;
    typedef iterator_property_map <Weights::iterator, EdgeIndexMap> WeightMap;
    // ...
    Weights weights; // = ...
    WeightMap wm(weights.begin(), edgeIds);
    // ...
    some_bgl_algorithm(g, wm);
    

    这里有一个完整的例子:

      using namespace boost;
    
      void sampleExteriorProperties()
      {
         typedef adjacency_list<vecS, vecS, undirectedS,
                                no_property,
                                //property<edge_index_t, int, property<edge_weight_t, int> >
                                property<edge_index_t, std::size_t>
                                > Graph;
         typedef graph_traits<Graph>::edge_descriptor Edge;
         typedef graph_traits<Graph>::edge_iterator EdgeIterator;
         typedef property_map<Graph, edge_index_t>::type EdgeIndexMap;
         //typedef property_map<Graph, edge_weight_t>::type WeightMap;
    
         const int NVERTICES = 5;
         const int NEDGES = 8;
    
         Graph g(NVERTICES);
    
         // Add edges WITH indexes.
         int edgeIndex = 0;
         add_edge(0, 1, edgeIndex++, g);
         add_edge(0, 2, edgeIndex++, g);
         add_edge(0, 3, edgeIndex++, g);
         add_edge(1, 2, edgeIndex++, g);
         add_edge(1, 4, edgeIndex++, g);
         add_edge(2, 3, edgeIndex++, g);
         add_edge(2, 4, edgeIndex++, g);
         add_edge(3, 4, edgeIndex++, g);
    
         // Weights: there must be a weight for every edge.
         // Weights will be later on accessed by edge index.
         assert(num_edges(g) == NEDGES);
         typedef std::vector<int> Weights;
         typedef std::vector<Weights> WeightsVector;
         WeightsVector weightVector({ { 2, 3, 5, 7, 9, 11, 13, 17 },
                                      { 8, 7, 6, 5, 4, 3, 2, 1 }
                                    });
    
         EdgeIndexMap edgeIds = get(edge_index, g);
    
         for (Weights &weights : weightVector)
         {
            // Use the iterator_property_map to read the properties from a
            // random access container. Remember: Edge ids are used to access
            // the correct value from the container!
            typedef iterator_property_map <Weights::iterator, EdgeIndexMap> WeightMap;
            WeightMap wm(weights.begin(), edgeIds);
    
            EdgeIterator eIt, eItEnd;
            tie(eIt, eItEnd) = edges(g);
            while (eIt!=eItEnd)
            {
               std::cout << *eIt << ": " << wm[*eIt] << " ";
               ++eIt;
            }
            std::cout << std::endl;
    
            // Explicitly pass the exterior map to the algorithm.
            std::vector<Edge> mstEdges;
            kruskal_minimum_spanning_tree(g, std::back_inserter(mstEdges),
                                          weight_map(wm));
    
            std::for_each(mstEdges.begin(), mstEdges.end(),
                          [](const Edge &val){std::cout << val << " ";});
            std::cout << std::endl;
         }
    
      }