【问题标题】:Combinations without repetition of elements in a list列表中不重复元素的组合
【发布时间】:2021-08-26 22:46:32
【问题描述】:

我有一个无向的 boost::adjacency_graph。给定一个顶点,我想找到所有以该顶点为源的边对。

例如,如果我有

0 --- 1 --- 2

0 和 2 的对将是空集,1 将是 ((1,0), (1,2))

0 --- 1 --- 2  
       \--- 3

0、2 和 3 的对将是空集,而 1 将是

((1,0), (1,2))
((1,0), (1,3))
((1,2), (1,3))

我在考虑类似的事情

std::vector<std::pair<edge, edge> edges;
for (const auto vertex : boost::make_iterator_range(boost::vertices(graph))) {
    for (const auto outEdge1 : boost::make_iterator_range(boost::out_edges(vertex, graph))) {
            for (const auto outEdge2 : boost::make_iterator_range(boost::out_edges(vertex, graph))) {
                if (outEdge != outEdge2) edges.push_back(outEdge1, outEdge2);
       }
   }
}

但这会失败,因为它会添加例如((1,0), (1, 2))((1,2), (1, 0))

我怎样才能避免这种情况?我认为这只是没有重复顶点外边的组合

考虑到边缘

(1,0) 
(1,2)
(1,3)

如何获得组合?

【问题讨论】:

  • 所以您只需要一种方法来消除当前答案集中的重复项?
  • 嗯...没有看到我所说的这个问题的重复,但STL + Ordered set + without duplicates 可能会为您指明一个好的方向。
  • 使用迭代器而不是 for 范围,类似于 (if (!out.empty()) for (auto it1 = out.begin(); std::next(it1) != out.end(); ++it1) { for (auto it2 = std::next(it1); it2 != out.end(); ++it2) { foo(*it1, *it2); } })。

标签: c++ boost graph combinations


【解决方案1】:

为了干净利落地做到这一点,我喜欢使用范围和combinations 算法。可悲的是,没有一个是标准化的,所以我们需要自己使用例如实现一些东西。 next_combination described here(以及许多其他地方)。

但是,为了快速演示,您可以将其编写为过滤的笛卡尔积:

这使用 Ranges-v3,因为“新”cartesian_product 还只是 a standards proposal

for(auto v : make_iterator_range(vertices(g))) {
    auto ee    = copy_range<EE>(make_iterator_range(out_edges(v, g)));
    auto combi = v::cartesian_product(ee, ee) | v::filter([](auto&& p) {
                     auto& [a, b] = p;
                     return a < b;
                 });

    fmt::print("Edge pairs from {}: {}\n", v, fmt::join(combi, "\n\t"));
}

作为完全错位的过早优化,我将EE 设为small_vector

这打印出 Live On Compiler Explorer

Edge pairs from 0:
Edge pairs from 1: ((1,0), (1,2))
        ((1,0), (1,3))
        ((1,2), (1,3))
Edge pairs from 2:
Edge pairs from 3:

现场演示

Live On Compiler Explorer

#include <boost/container/small_vector.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <range/v3/all.hpp>
using boost::make_iterator_range;
namespace r = ranges;
namespace v = r::views;

int main() {
    using G  = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
    using E  = G::edge_descriptor;
    using EE = boost::container::small_vector<E, 10>; // premature optimization :)
    G g;

    add_edge(0, 1, g);
    add_edge(1, 2, g);
    add_edge(1, 3, g);
    write_graphviz(std::cout, g);

    for(auto v : make_iterator_range(vertices(g))) {
        auto ee    = copy_range<EE>(make_iterator_range(out_edges(v, g)));
        auto combi = v::cartesian_product(ee, ee) | v::filter([](auto&& pair) {
                         auto& [a, b] = pair;
                         return a < b;
                     });

        fmt::print("Edge pairs from {}: {}\n", v, fmt::join(combi, "\n\t"));
    }
}

完整输出

graph G {
0;
1;
2;
3;
0--1 ;
1--2 ;
1--3 ;
}
Edge pairs from 0: 
Edge pairs from 1: ((1,0), (1,2))
    ((1,0), (1,3))
    ((1,2), (1,3))
Edge pairs from 2: 
Edge pairs from 3: 

【讨论】:

    猜你喜欢
    • 2023-02-19
    • 2018-11-03
    • 2017-07-26
    • 2012-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 2021-12-10
    相关资源
    最近更新 更多