【问题标题】:Can Boost Graph Find Connected Components Based on Weight?Boost Graph 可以根据权重找到连通分量吗?
【发布时间】:2021-07-30 09:45:24
【问题描述】:

我成功地使用 boost graph 的组件查找器来分配颜色,即组件的索引到我的图表中的每个顶点,如下所示:

#include <boost/graph/connected_components.hpp>
#include <boost/graph/adjacency_list.hpp>

boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> g;

std::vector<int> compon_map(boost::num_vertices(g));

int number_of_components = boost::connected_components(g, &compon_map[0]);

这将在我的模拟中的每次迭代之后产生不同的number_of_components(未显示),因为我这样做了

boost::clear_vertex(v, g);

在两者之间根据某些条件擦除一些边缘。

问题是,在我的模拟中,我想写出所有边的一些属性(比如权重),并且边迭代器的长度需要保持不变(数据集限制)。

因此,我的问题是:有没有办法传递一些边缘属性,比如

int L = boost::num_edges(g);

std::vector<bool> is_still_existent(L); // or
std::vector<double> edge_weights(L);

boost::connected_components(然后仅根据该属性计算边数)或者是否有另一种方法可以欺骗边迭代器即使在删除边后仍保持初始长度?

提前感谢任何提示:)

【问题讨论】:

  • 我对你的代码 sn-ps 感到困惑。由于使用了listS,因此如果没有外部顶点索引,这将无法工作。您能否使您的代码 sn-ps 在您的问题范围内自包含/一致?

标签: c++ boost boost-graph adjacency-list connected-components


【解决方案1】:

是的。您可以使用带有边缘过滤器的过滤图形适配器。我有几个答案up on SO 展示了如何使用它,但会看看我是否可以根据您的 sn-p 创建一个有用的示例。

所以我做了一个独立的样本¹:Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/random.hpp>
#include <boost/graph/graphviz.hpp>
#include <random>

using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
using V = G::vertex_descriptor;
using E = G::edge_descriptor;
using W = double;

int main(int argc, char** argv) {
    G g;
    auto seed = 9353; // fixed seed for demo
    if (argc > 1) {
        seed = atol(argv[1]);
        std::cerr << "Using PRNG seed: " << seed << "\n";
    }

    std::mt19937 engine(seed);
    auto weight_gen = bind(std::uniform_real_distribution<W>(0, 1), engine);
    boost::generate_random_graph(g, 10, 6, engine);

    std::map<E, W> weights;

    for (auto e : boost::make_iterator_range(edges(g)))
        weights[e] = weight_gen();
    
    std::vector<int> components(boost::num_vertices(g));
    auto cmap = boost::make_iterator_vertex_map(components.data());


    int n = boost::connected_components(g, cmap);

    std::cerr << n << " components\n";

    boost::dynamic_properties dp;
    dp.property("node_id", get(boost::vertex_index, g));
    dp.property("style", boost::make_constant_property<V>(std::string("filled")));
    dp.property("color",
                boost::make_transform_value_property_map(
                    [](int componentid) {
                        static std::array cc{"red",    "green", "yellow",
                                             "blue",   "brown", "black",
                                             "orange", "purple"};
                        return cc[componentid % cc.size()];
                    },
                    cmap));
    dp.property("label", boost::make_assoc_property_map(weights));

    boost::write_graphviz_dp(std::cout, g, dp);
}

生成伪随机图:

让我们为其添加一些过滤:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/graph/random.hpp>
#include <boost/graph/graphviz.hpp>
#include <random>

using G = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
using V = G::vertex_descriptor;
using E = G::edge_descriptor;
using W = double;

struct NonRemoved {
    std::set<E> const* _ref;
    bool operator()(E e) const { return not _ref->contains(e); }
};

int main(int argc, char** argv)
{
    G g;
    auto seed = 9353; // fixed seed for demo
    if (argc > 1) {
        seed = atol(argv[1]);
        std::cerr << "Using PRNG seed: " << seed << "\n";
    }

    std::mt19937 engine(seed);
    auto weight_gen = bind(std::uniform_real_distribution<W>(0, 1), engine);
    boost::generate_random_graph(g, 10, 6, engine);

    std::map<E, W> weights;

    for (auto e : boost::make_iterator_range(edges(g)))
        weights[e] = weight_gen();
    
    std::vector<int> components(boost::num_vertices(g));
    auto cmap = boost::make_iterator_vertex_map(components.data());

    auto random_edges = [&g] {
        auto [f,l] = edges(g);
        std::deque<E> re(f,l);
        std::random_shuffle(begin(re), end(re));
        return re;
    }();

    std::set<E> removed;
    NonRemoved predicate{&removed};

    boost::filtered_graph<G, NonRemoved, boost::keep_all> f(g, predicate, {});
    do {
        int n = boost::connected_components(f, cmap);
        std::cerr << n << " components\n";

        boost::dynamic_properties dp;
        dp.property("node_id", get(boost::vertex_index, f));
        dp.property("style", boost::make_constant_property<V>(std::string("filled")));
        dp.property("color",
                    boost::make_transform_value_property_map(
                        [](int componentid) {
                            static std::array cc{"red",    "green", "yellow",
                                                 "blue",   "brown", "black",
                                                 "orange", "purple"};
                            return cc[componentid % cc.size()];
                        },
                        cmap));
        dp.property("color",
                    boost::make_function_property_map<E>([&removed](E e) {
                        return removed.contains(e) ? "red" : "blue";
                    }));
        dp.property("label",
            boost::make_function_property_map<E>([&removed, &weights](E e) {
                if (removed.contains(e))
                    return std::string("REMOVED");
                return std::to_string(weights.at(e));
            }));

        std::ofstream ofs("graph_" + std::to_string(random_edges.size()) + ".dot");
        boost::write_graphviz_dp(ofs, f, dp);

        removed.insert(random_edges.front());
        random_edges.pop_front();
    } while (not random_edges.empty());
}

现在编写一系列graph_XXX.dot 图表,显示为:


¹(更改vertex container selector to vecS for simplicity

【讨论】:

  • 啊,感谢您早日接受。我只是想提出一个独立的例子,很有趣。
  • 非常感谢!与此同时,我发现了一个解决方法,我 确实 清除顶点,并坚持删除边缘,但给每个边缘一个 ID,然后当边缘的数量减少并且边缘迭代器不处理删除的边缘不再存在,我在背景中保存一个长度为零的全尺寸向量,同时我迭代剩余的边缘并将剩余的权重设置在零向量中。这样删除的边缘算作权重为零,我不必担心假删除它们,并将一些 is_removed bool 传递给 boost::conn_com
  • 哈哈,令人难以置信的是,你总是用一些解释得很糟糕的问题来制作一个完整的场景:D 非常感谢。是的,我希望你玩得开心!顺便提一句。我真的要感谢你对我论文的帮助,我正在海德堡完成我的物理学硕士学位。周末愉快!
  • 添加了一个带有过滤图的实时演示,逐步删除(随机)边缘(帧是倒序的rendered,因为这对我来说更美观:))
猜你喜欢
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-20
相关资源
最近更新 更多