怎样通过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]

0 0
原创粉丝点击