BGL BFS获取给定节点2深度内的所有节点

时间:2017-10-07 06:52:54

标签: c++ boost graph

我想知道Boost BGL BFS是否可用于查找从给定顶点到给定深度级别(例如2)的所有连接顶点。如果是这样,怎么样?

我对访问者的概念不是很熟悉,所以知道可以使用访问者来完成它会很有帮助。

谢谢!

2 个答案:

答案 0 :(得分:2)

考虑my answer yesterday,我意识到你的问题存在概念性问题。

无论如何距离是什么?

当您进行BFS时,您没有获得“实际”距离,您将获得“有效”距离,具体取决于顶点恰好被访问的顺序。这是有用的信息,但鉴于您正在寻找具有某个最大距离的节点,感觉您错过了这一部分。

确实,DFS给出了其他结果。如果你不关心使用哪种搜索策略,那就有好消息:boost::depth_first_visit采用可选的终止功能¹

如果您更换

breadth_first_search(g, s_source, 
            visitor(make_bfs_visitor(record_distances(distances.data(), on_tree_edge())))
            .color_map(colormap.data())
        );

  

查看 Live On Coliru

auto stop_when = [&](G::vertex_descriptor vd, ...) { return distances.at(vd)>=2.0; };

depth_first_visit(g, s_source,
        make_dfs_visitor(record_distances(distances.data(), on_tree_edge())),
        colormap.data(),
        stop_when
    );

你可以让算法减少工作量,所以你得到第二张图像而不是第一张图像:

  

更高的准确度

沿着这条路走得更远,你可能会发现你一直想要最短的路径。实际上,使用dijkstra_shortest_paths会更准确(如果边缘具有单位重量,则恰好相当于BFS)。

参见 Dijkstra Live On Coliru

您会注意到无法在某个限制下修剪最短路径树。

根据您的实际可扩展性要求和其他限制,r_c_shortest_paths可能会有所帮助:

  

资源约束的最短路径问题(SPPRC)在有向图中寻找最短(最便宜,最快)的路径,其具有从原始节点到受一个或多个资源影响的目标节点的任意弧长(传播时间,成本)约束

     

例如,可以根据

的约束寻找从s到t的最小长度的路径      
      
  • 总旅行时间不得超过某个上限和/或
  •   
  • 在路径顶点处必须拾取的某些商品的总量小于或等于某个容量限制和/或
  •   
  • 如果在路径上访问了两个顶点i和j,则必须在j
  • 之前访问   
  •   
     

强烈意义上的问题是NP难的[...]

¹我觉得有点意义,DFS有一个终止函数更自然,BFS不能(因为BFS会在下降到搜索树中的子节点之前递归访问所有对等体;这很容易导致由于一个分支被终止,所以跳过了整块树木。我想可以在BF访问算法中添加类似的机制。

答案 1 :(得分:1)

因此。我决定尝试一下:你通过以下方式使用distance_recorder

breadth_first_search(g, s_source, visitor(make_bfs_visitor(
        record_distances(distances.data(), on_tree_edge())
    ))
);

示例程序

<强> Live On Coliru

using G = adjacency_list<>;
G::vertex_descriptor s_source = 8;

template<typename G> void save_graph(G const& g, std::string const& name, std::vector<double> const& distances);
void save_graph_filtered(double threshold, G const& g, std::string const& name, std::vector<double> const& distances);
G generate();

int main() {
    G g = generate();

    std::vector<double> distances(num_vertices(g));
    std::vector<default_color_type> colormap(num_vertices(g));

    breadth_first_search(g, s_source, 
                visitor(make_bfs_visitor(record_distances(distances.data(), on_tree_edge())))
                .color_map(colormap.data())
    );

    for (auto vd : make_iterator_range(vertices(g)))
        if (colormap.at(vd) == default_color_type{}) 
            distances.at(vd) = -1;

    distances[s_source] = -2;
    save_graph(g, "dotgraph.txt", distances);

    // show only nodes at distance <= 2:
    save_graph_filtered(2.0, g, "dotgraph-filtered.txt", distances);
}

生成随机图

这很简单,因为BGL有它:

////////////////////////////////////////////
// generate random graph
#include <boost/graph/random.hpp>
#include <random>

size_t s_seed = 0xf5cab8bd; // std::random_device{}();
std::mt19937 s_rng {s_seed};

G generate() {
    G g;
    std::cout << "Seed used: " << std::hex << std::showbase << s_seed << "\n";
    boost::generate_random_graph(g, 20, 30, s_rng);
    return g;
}
  

硬编码种子复制了这篇文章中的图像

过滤阈值距离

这也很简单:

////////////////////////////////////////////
// filtering for threshold distance
#include <boost/graph/filtered_graph.hpp>
void save_graph_filtered(double threshold, G const& g, std::string const& name, std::vector<double> const& distances) {
    filtered_graph<G, keep_all, std::function<bool(G::vertex_descriptor)>> 
        fg(g, {}, [&](G::vertex_descriptor vd) { return distances[vd]!=-1 && distances[vd]<=threshold; });

    save_graph(fg, name, distances);
}
  

请注意检查distance != -1以排除无法到达的顶点。

保存漂亮的Graphviz文件

这是最不必要的部分,但它有很好的演示:

////////////////////////////////////////////
// graph-viz demo output
#include <fstream>
#include <algorithm>
#include <sstream>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/graph/graphviz.hpp>

template<typename G>
void save_graph(G const& g, std::string const& name, std::vector<double> const& distances) {
    using Vertex = typename G::vertex_descriptor;
    std::ofstream dotfile;
    dotfile.open(name);

    auto shape = [&distances](Vertex vd) {
        return (vd==s_source)?"circle":"Mrecord";
    };

    auto label = [&distances](Vertex vd) {
        std::ostringstream name;
        if (vd == s_source)                 name << "SOURCE";
        else                                name << vd;
        if (auto d = distances[vd]; d >= 0) name << "|distance: " << d;
        return name.str();
    };

    auto max = 1.25* *std::max_element(distances.begin(), distances.end());
    auto dist = [&distances,max](Vertex vd) {
        int r = 224, g = 160, b = 160;
        if (auto d = distances[vd]; d >= 0) {
            r = 255.0 * (1.0 - std::clamp(d, 0.0, max)/max);
            g = 255.0 * (1.0 - std::clamp(d, 0.0, max)/max);
            b = 255;
        }
        std::ostringstream oss;
        oss << std::setfill('0') << '#' << std::hex
            << std::setw(2) << r
            << std::setw(2) << g
            << std::setw(2) << b;
        return oss.str();
    };

    dynamic_properties dp;
    typed_identity_property_map<Vertex> v_;

    dp.property("node_id", get(vertex_index, g));
    dp.property("label", make_transform_value_property_map(label, v_));
    dp.property("shape", make_transform_value_property_map(shape, v_));
    //dp.property("shape", make_constant_property<Vertex>("Mrecord"s));
    dp.property("style", make_constant_property<Vertex>("filled"s));
    dp.property("fillcolor", make_transform_value_property_map(dist, v_));

    write_graphviz_dp(dotfile, g, dp);
}

输出:

未筛选:

enter image description here

过滤阈值(样本中的2.0):

enter image description here

相关问题