Boost BGL BFS查找从源到目标的所有唯一路径

编程入门 行业动态 更新时间:2024-10-08 10:37:09
本文介绍了Boost BGL BFS查找从源到目标的所有唯一路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在使用Boost BGL C ++,我需要图从源顶点到目标顶点进行BFS并返回所有唯一路径.

现在,我想到了一种使用过滤后的图来获取包含从源到目标的路径的图子集的方法,但是我意识到,由于过滤后的图包括被访问但不包含顶点的顶点,所以基本上不进行过滤从源到目标的路径.有什么方法可以获取这些信息,或者采用其他方法更好?

参考代码:

boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> Graph::getUniquePathsFromSource(VertexDescr source, VertexDescr target, DirectedGraph const & g) { std::vector<double> distances(num_vertices(g)); std::vector<boost::default_color_type> colormap(num_vertices(g)); // Run BFS and record all distances from the source node breadth_first_search(g, source, visitor(make_bfs_visitor(boost::record_distances(distances.data(), boost::on_tree_edge()))) .color_map(colormap.data()) ); for (auto vd : boost::make_iterator_range(vertices(g))) if (colormap.at(vd) == boost::default_color_type{}) distances.at(vd) = -1; distances[source] = -2; boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> fg(g, {}, [&](VertexDescr vd) { return distances[vd] != -1; }); // Print edge list std::cout << "filtered out-edges:" << std::endl; std::cout << "Source Vertex: " << source << std::endl; auto ei = boost::edges(fg); typedef boost::property_map<DirectedGraph, boost::edge_weight_t>::type WeightMap; WeightMap weights = get(boost::edge_weight, fg); for (auto it = ei.first; it != ei.second; ++it) { if (source != boost::target(*it, g)) { std::cout << "Edge Probability " << *it << ": " << get(weights, *it) << std::endl; } } return fg; }

输入(顶点1,顶点2,权重):

0 1 0.001 0 2 0.1 0 3 0.001 1 5 0.001 2 3 0.001 3 4 0.1 1 482 0.1 482 635 0.001 4 705 0.1 705 5 0.1 1 1491 0.01 1 1727 0.01 1 1765 0.01

输出(对于Source = 0,Target = 5):

Source Vertex: 0 Edge Probability (0,1): 0.001 Edge Probability (0,2): 0.1 Edge Probability (0,3): 0.001 Edge Probability (1,5): 0.001 Edge Probability (1,482): 0.1 Edge Probability (1,1491): 0.01 Edge Probability (1,1727): 0.01 Edge Probability (1,1765): 0.01 Edge Probability (2,3): 0.001 Edge Probability (3,4): 0.1 Edge Probability (4,705): 0.1 Edge Probability (482,635): 0.001 Edge Probability (705,5): 0.1

预期输出:

0->1->5 0->3->4->705->5 0->2->3->4->705->5

解决方案

我不会使用BFS算法,因为它使用颜色映射来跟踪访问的节点.但是,如果要所有个不同的路径,则不想跳过已访问的节点(因为那样的话,您可以跳过其他路径).

相反,我将实现蛮力广度优先的递归算法,该算法仅访问所有相邻节点,除非它们已经在当前路径中.

所需的所有状态都是当前路径.

此想法的详细解释如下: www.quora/How-should-I-find-all-distinct-simple-paths-between-2-given-nodes-在无向图中

在Coliru上直播 #include <boost/graph/adjacency_list.hpp> #include <boost/graph/graph_utility.hpp> // print_graph using namespace boost; using Graph = adjacency_list<vecS, listS, directedS, property<vertex_index_t, int>, property<edge_weight_t, double> >; Graph read_graph(); using Vertex = Graph::vertex_descriptor; using Path = std::vector<Vertex>; template <typename Report> void all_paths_helper(Vertex from, Vertex to, Graph const& g, Path& path, Report const& callback) { path.push_back(from); if (from == to) { callback(path); } else { for (auto out : make_iterator_range(out_edges(from, g))) { auto v = target(out, g); if (path.end() == std::find(path.begin(), path.end(), v)) { all_paths_helper(v, to, g, path, callback); } } } path.pop_back(); } template <typename Report> void all_paths(Vertex from, Vertex to, Graph const& g, Report const& callback) { Path state; all_paths_helper(from, to, g, state, callback); } int main() { auto g = read_graph(); print_graph(g, std::cout); auto by_vertex_id = [&](int id) { return *find_if(vertices(g), [&](Vertex vd) { return id == get(vertex_index, g, vd); }); }; all_paths(by_vertex_id(0), by_vertex_id(5), g, [&](Path const& path) { std::cout << "Found path "; for (auto v : path) std::cout << get(vertex_index, g, v) << " "; std::cout << "\n"; }); std::cout.flush(); } // immaterial to the task, reading the graph Graph read_graph() { std::istringstream iss(R"( 0 1 0.001 0 2 0.1 0 3 0.001 1 5 0.001 2 3 0.001 3 4 0.1 1 482 0.1 482 635 0.001 4 705 0.1 705 5 0.1 1 1491 0.01 1 1727 0.01 1 1765 0.01)"); Graph g; auto vertex = [&,idx=std::map<int,Vertex>{}](int id) mutable { auto it = idx.find(id); if (it != idx.end()) return it->second; return idx.emplace(id, add_vertex(id, g)).first->second; }; for (std::string line; getline(iss, line);) { std::istringstream ls(line); int s,t; double w; if (ls >> s >> t >> w) { add_edge(vertex(s), vertex(t), w, g); } else { std::cerr << "Skipped invalid line '" << line << "'\n"; } } return g; }

哪些印刷品:

1 --> 5 482 1491 1727 1765 0 --> 1 2 3 2 --> 3 3 --> 4 5 --> 4 --> 705 482 --> 635 635 --> 705 --> 5 1491 --> 1727 --> 1765 --> Found path 0 1 5 Found path 0 2 3 4 705 5 Found path 0 3 4 705 5

I am using Boost BGL C++ and I need the Graph to do a BFS from a Source vertex to a target vertex and return all the unique paths.

Right now, I thought of a way to use a filtered graph to get a subset of the graph containing paths from source to target but i realised that it was basically not filtering since the filtered graph included vertex that are visited but not part of a path from source to target. Is there any way to get this information or a different approach is better?

Code for reference:

boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> Graph::getUniquePathsFromSource(VertexDescr source, VertexDescr target, DirectedGraph const & g) { std::vector<double> distances(num_vertices(g)); std::vector<boost::default_color_type> colormap(num_vertices(g)); // Run BFS and record all distances from the source node breadth_first_search(g, source, visitor(make_bfs_visitor(boost::record_distances(distances.data(), boost::on_tree_edge()))) .color_map(colormap.data()) ); for (auto vd : boost::make_iterator_range(vertices(g))) if (colormap.at(vd) == boost::default_color_type{}) distances.at(vd) = -1; distances[source] = -2; boost::filtered_graph<DirectedGraph, boost::keep_all, std::function<bool(VertexDescr)>> fg(g, {}, [&](VertexDescr vd) { return distances[vd] != -1; }); // Print edge list std::cout << "filtered out-edges:" << std::endl; std::cout << "Source Vertex: " << source << std::endl; auto ei = boost::edges(fg); typedef boost::property_map<DirectedGraph, boost::edge_weight_t>::type WeightMap; WeightMap weights = get(boost::edge_weight, fg); for (auto it = ei.first; it != ei.second; ++it) { if (source != boost::target(*it, g)) { std::cout << "Edge Probability " << *it << ": " << get(weights, *it) << std::endl; } } return fg; }

Input (vertex1, vertex2, weight):

0 1 0.001 0 2 0.1 0 3 0.001 1 5 0.001 2 3 0.001 3 4 0.1 1 482 0.1 482 635 0.001 4 705 0.1 705 5 0.1 1 1491 0.01 1 1727 0.01 1 1765 0.01

Output (For Source = 0, Target = 5):

Source Vertex: 0 Edge Probability (0,1): 0.001 Edge Probability (0,2): 0.1 Edge Probability (0,3): 0.001 Edge Probability (1,5): 0.001 Edge Probability (1,482): 0.1 Edge Probability (1,1491): 0.01 Edge Probability (1,1727): 0.01 Edge Probability (1,1765): 0.01 Edge Probability (2,3): 0.001 Edge Probability (3,4): 0.1 Edge Probability (4,705): 0.1 Edge Probability (482,635): 0.001 Edge Probability (705,5): 0.1

Expected Output:

0->1->5 0->3->4->705->5 0->2->3->4->705->5

解决方案

I wouldn't use the BFS algorithm because it uses colormaps to track visited nodes. However, if you want all distinct paths you will not want to skip already-visited nodes (because you may skip alternative paths then).

Instead, I'd implement a brute-force breadth-first recursive algorithm that simply visits all adjacent nodes unless they're already in the current path.

All state required is the current path.

The idea is explained in more detail here: www.quora/How-should-I-find-all-distinct-simple-paths-between-2-given-nodes-in-an-undirected-graph

Live On Coliru

#include <boost/graph/adjacency_list.hpp> #include <boost/graph/graph_utility.hpp> // print_graph using namespace boost; using Graph = adjacency_list<vecS, listS, directedS, property<vertex_index_t, int>, property<edge_weight_t, double> >; Graph read_graph(); using Vertex = Graph::vertex_descriptor; using Path = std::vector<Vertex>; template <typename Report> void all_paths_helper(Vertex from, Vertex to, Graph const& g, Path& path, Report const& callback) { path.push_back(from); if (from == to) { callback(path); } else { for (auto out : make_iterator_range(out_edges(from, g))) { auto v = target(out, g); if (path.end() == std::find(path.begin(), path.end(), v)) { all_paths_helper(v, to, g, path, callback); } } } path.pop_back(); } template <typename Report> void all_paths(Vertex from, Vertex to, Graph const& g, Report const& callback) { Path state; all_paths_helper(from, to, g, state, callback); } int main() { auto g = read_graph(); print_graph(g, std::cout); auto by_vertex_id = [&](int id) { return *find_if(vertices(g), [&](Vertex vd) { return id == get(vertex_index, g, vd); }); }; all_paths(by_vertex_id(0), by_vertex_id(5), g, [&](Path const& path) { std::cout << "Found path "; for (auto v : path) std::cout << get(vertex_index, g, v) << " "; std::cout << "\n"; }); std::cout.flush(); } // immaterial to the task, reading the graph Graph read_graph() { std::istringstream iss(R"( 0 1 0.001 0 2 0.1 0 3 0.001 1 5 0.001 2 3 0.001 3 4 0.1 1 482 0.1 482 635 0.001 4 705 0.1 705 5 0.1 1 1491 0.01 1 1727 0.01 1 1765 0.01)"); Graph g; auto vertex = [&,idx=std::map<int,Vertex>{}](int id) mutable { auto it = idx.find(id); if (it != idx.end()) return it->second; return idx.emplace(id, add_vertex(id, g)).first->second; }; for (std::string line; getline(iss, line);) { std::istringstream ls(line); int s,t; double w; if (ls >> s >> t >> w) { add_edge(vertex(s), vertex(t), w, g); } else { std::cerr << "Skipped invalid line '" << line << "'\n"; } } return g; }

Which prints:

1 --> 5 482 1491 1727 1765 0 --> 1 2 3 2 --> 3 3 --> 4 5 --> 4 --> 705 482 --> 635 635 --> 705 --> 5 1491 --> 1727 --> 1765 --> Found path 0 1 5 Found path 0 2 3 4 705 5 Found path 0 3 4 705 5

更多推荐

Boost BGL BFS查找从源到目标的所有唯一路径

本文发布于:2023-11-30 18:27:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1651062.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路径   目标   Boost   BGL   BFS

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!