怎样通过boost库的breadth_first_search算法查找点到点的最短路径
来源:互联网 发布:权志龙水原希子 知乎 编辑:程序博客网 时间:2024/05/07 13:34
From:http://stackoverflow.com/questions/8950188/is-it-possible-to-apply-breadth-first-search-algorithm-of-boost-library-to-matri/8953750#8953750
我的任务是找出矩阵中一个点到另一个点的最短路径,且只能按照上下左右移动
0 0 0 0 1 0 0 01 0 0 0 0 0 0 00 0 0 1 0 1 F 00 1 0 1 0 0 0 00 0 0 1 0 0 0 00 S 0 1 0 0 1 00 0 0 0 0 0 1 00 0 0 0 0 0 1 0
S - 起点
F - 终点
0 - 可以穿过的点
1 - 不能穿过的点
很明显广度优先搜索是解决该问题的最佳方法,我知道Boost库支持该算法,但是我对Boost库不是特别熟悉。
我如何使用Boost库的广度优先搜索算法解决我的问题?据我了解,Boost库的广度优先搜索算法是专门为图而设计的,我感觉把m*n的矩阵转换成一个包含m*n个点和m*(n-1) + (m-1)*n条边的图不是一个好主意
我可以直接将Boost库的广度优先搜索算法应用于矩阵(不是转换成图)吗,或者是能使用我自己定义的函数就更好了?
注:以上是对提问者的翻译
以下是对回答者的翻译:
(首先很抱歉给的答案篇幅这么长。我使用Boost Graph Library已经有些日子了,写这些也可以很好的复习一下。全部代码在最底部)
Boost图形库(和通常的泛型编程)的好处就在于你不需要在既定的算法中使用特定的数据结构。你上述提到的遍历矩阵的规则已经和图差不多了,你需要做的就是将这些规则归纳成可以被BGL(Boost图形库)算法使用的traits class。
明确的说,就是我们要为你的graph定义一个特定的boost::graph_traits<T>
结构。让我们假定你的矩阵是一个以行优先的int型的一维数组。但很不幸的是,只包含int[N]的graph_traits
是不够的,因为它没有提供矩阵中维度的信息。所以我们按照以下形式定义你的graph:
namespace matrix{ typedef int cell; static const int FREE = 0; static const int WALL = 1; template< size_t ROWS, size_t COLS > struct graph { cell cells[ROWS*COLS]; };}
我这里使用了一个数组来表示单元格数据,如果在外面管理这些数据的话你可以使用指针更简单一些。现在我们已经有了一个可以用于graph_traits
的表示矩阵的类型了,但是首先让我们定义一些我们需要的类型和函数:
顶点类型和辅助函数:
namespace matrix{ typedef size_t vertex_descriptor; template< size_t ROWS, size_t COLS > size_t get_row( vertex_descriptor vertex, graph< ROWS, COLS > const & ) { return vertex / COLS; } template< size_t ROWS, size_t COLS > size_t get_col( vertex_descriptor vertex, graph< ROWS, COLS > const & ) { return vertex % COLS; } template< size_t ROWS, size_t COLS > vertex_descriptor make_vertex( size_t row, size_t col, graph< ROWS, COLS > const & ) { return row * COLS + col; }}
遍历顶点的类型和函数:
namespace matrix{ typedef const cell * vertex_iterator; template< size_t ROWS, size_t COLS > std::pair< vertex_iterator, vertex_iterator > vertices( graph< ROWS, COLS > const & g ) { return std::make_pair( g.cells, g.cells + ROWS*COLS ); } typedef size_t vertices_size_type; template< size_t ROWS, size_t COLS > vertices_size_type num_vertices( graph< ROWS, COLS > const & g ) { return ROWS*COLS; }}
边类型:
namespace matrix{ typedef std::pair< vertex_descriptor, vertex_descriptor > edge_descriptor; bool operator==( edge_descriptor const & lhs, edge_descriptor const & rhs ) { return lhs.first == rhs.first && lhs.second == rhs.second || lhs.first == rhs.second && lhs.second == rhs.first; } bool operator!=( edge_descriptor const & lhs, edge_descriptor const & rhs ) { return !(lhs == rhs); }}
最后,迭代器和函数来帮助我们遍历出顶点和边存在的关联关系:
namespace matrix{ template< size_t ROWS, size_t COLS > vertex_descriptor source( edge_descriptor const & edge, graph< ROWS, COLS > const & ) { return edge.first; } template< size_t ROWS, size_t COLS > vertex_descriptor target( edge_descriptor const & edge, graph< ROWS, COLS > const & ) { return edge.second; } typedef boost::shared_container_iterator< std::vector< edge_descriptor > > out_edge_iterator; template< size_t ROWS, size_t COLS > std::pair< out_edge_iterator, out_edge_iterator > out_edges( vertex_descriptor vertex, graph< ROWS, COLS > const & g ) { boost::shared_ptr< std::vector< edge_descriptor > > edges( new std::vector< edge_descriptor >() ); if( g.cells[vertex] == FREE ) { size_t row = get_row( vertex, g ), col = get_col( vertex, g ); if( row != 0 ) { vertex_descriptor up = make_vertex( row - 1, col, g ); if( g.cells[up] == FREE ) edges->push_back( edge_descriptor( vertex, up ) ); } if( row != ROWS-1 ) { vertex_descriptor down = make_vertex( row + 1, col, g ); if( g.cells[down] == FREE ) edges->push_back( edge_descriptor( vertex, down ) ); } if( col != 0 ) { vertex_descriptor left = make_vertex( row, col - 1, g ); if( g.cells[left] == FREE ) edges->push_back( edge_descriptor( vertex, left ) ); } if( col != COLS-1 ) { vertex_descriptor right = make_vertex( row, col + 1, g ); if( g.cells[right] == FREE ) edges->push_back( edge_descriptor( vertex, right ) ); } } return boost::make_shared_container_range( edges ); } typedef size_t degree_size_type; template< size_t ROWS, size_t COLS > degree_size_type out_degree( vertex_descriptor vertex, graph< ROWS, COLS > const & g ) { std::pair< out_edge_iterator, out_edge_iterator > edges = out_edges( vertex, g ); return std::distance( edges.first, edges.second ); }}
到现在未知我们已经定义好了我们需要的boost::graph_traits
结构
namespace boost{ template< size_t ROWS, size_t COLS > struct graph_traits< matrix::graph< ROWS, COLS > > { typedef matrix::vertex_descriptor vertex_descriptor; typedef matrix::edge_descriptor edge_descriptor; typedef matrix::out_edge_iterator out_edge_iterator; typedef matrix::vertex_iterator vertex_iterator; typedef boost::undirected_tag directed_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : virtual boost::vertex_list_graph_tag, virtual boost::incidence_graph_tag {}; typedef matrix::vertices_size_type vertices_size_type; typedef matrix::degree_size_type degree_size_type; static vertex_descriptor null_vertex() { return ROWS*COLS; } };}
接下来就是如何展示使用BFS算法查找最短路径:
int main(){ const size_t rows = 8, cols = 8; using namespace matrix; typedef graph< rows, cols > my_graph; my_graph g = { FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, WALL, FREE, FREE, FREE, WALL, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, }; const vertex_descriptor start_vertex = make_vertex( 5, 1, g ), finish_vertex = make_vertex( 2, 6, g ); vertex_descriptor predecessors[rows*cols] = { 0 }; using namespace boost; breadth_first_search( g, start_vertex, visitor( make_bfs_visitor( record_predecessors( predecessors, on_tree_edge() ) ) ). vertex_index_map( identity_property_map() ) ); typedef std::list< vertex_descriptor > path; path p; for( vertex_descriptor vertex = finish_vertex; vertex != start_vertex; vertex = predecessors[vertex] ) p.push_front( vertex ); p.push_front( start_vertex ); for( path::const_iterator cell = p.begin(); cell != p.end(); ++cell ) std::cout << "[" << get_row( *cell, g ) << ", " << get_col( *cell, g ) << "]\n" ; return 0;}
以下是输出的从起点到终点的最短路径:
[5, 1][4, 1][4, 2][3, 2][2, 2][1, 2][1, 3][1, 4][1, 5][1, 6][2, 6]
源码如下:
#include <boost/graph/graph_traits.hpp>#include <boost/graph/breadth_first_search.hpp>#include <boost/graph/visitors.hpp>#include <boost/shared_container_iterator.hpp>#include <boost/shared_ptr.hpp>#include <vector>#include <boost/iterator/counting_iterator.hpp>#include <list>namespace matrix{ typedef int cell; static const int FREE = 0; static const int WALL = 1; template< size_t ROWS, size_t COLS > struct graph { cell cells[ROWS*COLS]; }; typedef size_t vertex_descriptor; template< size_t ROWS, size_t COLS > size_t get_row( vertex_descriptor vertex, graph< ROWS, COLS > const & ) { return vertex / COLS; } template< size_t ROWS, size_t COLS > size_t get_col( vertex_descriptor vertex, graph< ROWS, COLS > const & ) { return vertex % COLS; } template< size_t ROWS, size_t COLS > vertex_descriptor make_vertex( size_t row, size_t col, graph< ROWS, COLS > const & ) { return row * COLS + col; } typedef const cell * vertex_iterator; template< size_t ROWS, size_t COLS > std::pair< vertex_iterator, vertex_iterator > vertices( graph< ROWS, COLS > const & g ) { return std::make_pair( g.cells, g.cells + ROWS*COLS ); } typedef size_t vertices_size_type; template< size_t ROWS, size_t COLS > vertices_size_type num_vertices( graph< ROWS, COLS > const & g ) { return ROWS*COLS; } typedef std::pair< vertex_descriptor, vertex_descriptor > edge_descriptor; bool operator==( edge_descriptor const & lhs, edge_descriptor const & rhs ) { return lhs.first == rhs.first && lhs.second == rhs.second || lhs.first == rhs.second && lhs.second == rhs.first; } bool operator!=( edge_descriptor const & lhs, edge_descriptor const & rhs ) { return !(lhs == rhs); } template< size_t ROWS, size_t COLS > vertex_descriptor source( edge_descriptor const & edge, graph< ROWS, COLS > const & ) { return edge.first; } template< size_t ROWS, size_t COLS > vertex_descriptor target( edge_descriptor const & edge, graph< ROWS, COLS > const & ) { return edge.second; } typedef boost::shared_container_iterator< std::vector< edge_descriptor > > out_edge_iterator; template< size_t ROWS, size_t COLS > std::pair< out_edge_iterator, out_edge_iterator > out_edges( vertex_descriptor vertex, graph< ROWS, COLS > const & g ) { boost::shared_ptr< std::vector< edge_descriptor > > edges( new std::vector< edge_descriptor >() ); if( g.cells[vertex] == FREE ) { size_t row = get_row( vertex, g ), col = get_col( vertex, g ); if( row != 0 ) { vertex_descriptor up = make_vertex( row - 1, col, g ); if( g.cells[up] == FREE ) edges->push_back( edge_descriptor( vertex, up ) ); } if( row != ROWS-1 ) { vertex_descriptor down = make_vertex( row + 1, col, g ); if( g.cells[down] == FREE ) edges->push_back( edge_descriptor( vertex, down ) ); } if( col != 0 ) { vertex_descriptor left = make_vertex( row, col - 1, g ); if( g.cells[left] == FREE ) edges->push_back( edge_descriptor( vertex, left ) ); } if( col != COLS-1 ) { vertex_descriptor right = make_vertex( row, col + 1, g ); if( g.cells[right] == FREE ) edges->push_back( edge_descriptor( vertex, right ) ); } } return boost::make_shared_container_range( edges ); } typedef size_t degree_size_type; template< size_t ROWS, size_t COLS > degree_size_type out_degree( vertex_descriptor vertex, graph< ROWS, COLS > const & g ) { std::pair< out_edge_iterator, out_edge_iterator > edges = out_edges( vertex, g ); return std::distance( edges.first, edges.second ); }}namespace boost{ template< size_t ROWS, size_t COLS > struct graph_traits< matrix::graph< ROWS, COLS > > { typedef matrix::vertex_descriptor vertex_descriptor; typedef matrix::edge_descriptor edge_descriptor; typedef matrix::out_edge_iterator out_edge_iterator; typedef matrix::vertex_iterator vertex_iterator; typedef boost::undirected_tag directed_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : virtual boost::vertex_list_graph_tag, virtual boost::incidence_graph_tag {}; typedef matrix::vertices_size_type vertices_size_type; typedef matrix::degree_size_type degree_size_type; static vertex_descriptor null_vertex() { return ROWS*COLS; } };}int main(){ const size_t rows = 8, cols = 8; using namespace matrix; typedef matrix::graph< rows, cols > my_graph; my_graph g = { FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, WALL, FREE, FREE, FREE, WALL, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, FREE, FREE, FREE, FREE, FREE, FREE, WALL, FREE, }; const vertex_descriptor start_vertex = make_vertex( 5, 1, g ), finish_vertex = make_vertex( 2, 6, g ); vertex_descriptor predecessors[rows*cols] = { 0 }; using namespace boost; breadth_first_search( g, start_vertex, visitor( make_bfs_visitor( record_predecessors( predecessors, on_tree_edge() ) ) ). vertex_index_map( boost::identity_property_map() ) ); typedef std::list< vertex_descriptor > path; path p; for( vertex_descriptor vertex = finish_vertex; vertex != start_vertex; vertex = predecessors[vertex] ) p.push_front( vertex ); p.push_front( start_vertex ); for( path::const_iterator cell = p.begin(); cell != p.end(); ++cell ) std::cout << "[" << get_row( *cell, g ) << ", " << get_col( *cell, g ) << "]\n" ; return 0;}输出:
[5, 1] [4, 1] [4, 2] [3, 2] [2, 2] [1, 2] [1, 3] [1, 4] [1, 5] [1, 6] [2, 6]
- 怎样通过boost库的breadth_first_search算法查找点到点的最短路径
- BFS--点到点间的最短路径
- 所有点对的最短路径-FloydWarshall算法
- 所有点对的最短路径-FloydWarshall算法
- Floyd_任意点之间的最短路径算法
- 使用佛洛伊德算法计算点对的最短路径
- 动态规划求解国际象棋中车点到点的最短路径总数
- 最简单的最短路径算法
- 图中点到点最短路径长度
- 点对的最短路径问题
- Dijkatra 算法 计算一个点到其他点的最短路径
- Dijkstra算法求任意点到其它点的最短路径
- 最短路径的算法的学习
- floyd最短路径算法的实现
- 同样经典的最短路径算法
- A*算法的最短路径实现!
- Dijkstra算法的最短路径实现
- 最短路径的SPFA算法
- SpringMVC自动登录功能
- 设计模式学习笔记(五):建造者模式【Builder Pattern】(一)问题提出
- SAP财务会计学习
- GCC __attribute__ meaning (reference for https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Att)
- ios 日期操作封装
- 怎样通过boost库的breadth_first_search算法查找点到点的最短路径
- OpenCV数字图像处理(4) 平移
- 四大组件之BroadcastReceiver
- Linux的Init程序与系统服务管理
- Hadoop Exception: java.lang.IllegalArgumentException: Does not contain a valid host:port authority:
- minicom & runscript 介绍
- NSUserDefaults存储mutable类型实例
- perl 引用/hash
- javascript (function(){})()