怎样通过boost库的breadth_first_search算法查找点到点的最短路径

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 0
1 0 0 0 0 0 0 0
0 0 0 1 0 1 F 0
0 1 0 1 0 0 0 0
0 0 0 1 0 0 0 0
0 S 0 1 0 0 1 0
0 0 0 0 0 0 1 0
0 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算法查找点到点的最短路径

时间: 2024-10-19 10:56:37

怎样通过boost库的breadth_first_search算法查找点到点的最短路径的相关文章

(三)Boost库之字符串处理

(三)Boost库之字符串处理 字符串处理一直是c/c++的弱项,string_algo库很好的弥补了这一点. string_algo 库算法命名规则: 前缀i    : 有这个前缀表名算法的大小写不敏感,否则大小写敏感 后缀_copy:  有这个后缀表明算法不变动输入,返回处理结果的拷贝,否则算法原地处理 后缀_if  :  有这个后缀表明算法需要一个作为判断式的谓词函数对象,否则使用默认的判断准则 string_algo库提供的算法共分五大类,如下: [1]大小写转换: [2]判断式与分类:

2015-03-12---外观模式,建造者模式(附代码),观察者模式(附代码),boost库应用

今天白天主要看了boost库的应用,主要是经常使用的一些库,array,bind,function,regex,thread,unordered,ref,smartpointers库,晚上看了看设计模式.主要就是外观模式.建造者模式和观察者模式.我们从boost简要说起. 事实上boost的库好多东西在c++11里面已经有了.比方bind,仅仅只是boost的库的bind比c++11用着感觉要方便.事实上有些东西我自己由于也没实用c++做过什么大的项目.所以不敢乱说,仅仅敢说点建议性的,关于bi

2015-03-12---外观模式,建造者模式,观察者模式,boost库应用

今天白天主要看了boost库的应用,主要是常用的一些库,array,bind,function,regex,thread,unordered,ref,smartpointers库,晚上看了看设计模式,主要就是外观模式,建造者模式和观察者模式.我们从boost简要说起. 其实boost的库好多东西在c++11里面已经有了,比如bind,只不过boost的库的bind比c++11用着感觉要方便,其实有些东西我自己因为也没有用c++做过什么大的项目,所以不敢乱说,只敢说点建议性的,关于bind就是绑定

BOOST 库中filesyatem 库的学习

/*FileSyatem 库的学习 ------------------------------------------------------------------------------------------------------------库的使用方式 嵌入源码的形式: #define BOOST_SYSTEN_NO_LIB #define BOOST_FILESYSTEM_NO_LIB #include<boost\filesystem.hpp> ----------------

boost库在工作(15)绑定器与函数对象之三

前面已经可以优美地解决两个参数的函数给算法for_each调用了,但是又会遇到这样的一种情况,当需要三个参数或者三个以上的参数给算法for_each调用呢?从STL里的绑定器bind1st,显然是不行了,因为它最多只支持两个参数,那还有什么办法呢?这时就需要使用boost库里强大的绑定器bind了.它不仅适用的情况比STL库里的多,还更加方便,更加人性化.下面就来看看怎么样绑定三个参数的类成员函数的例子,如下: [cpp] view plaincopy //调用类的成员函数,但参数两个以上. /

c++ boost库学习三:实用工具

noncopyable 大家都知道定义一个空类的时候,它实际包含了构造函数,拷贝构造函数,赋值操作符和析构函数等. 这样就很容易产生一个问题,就是当用户调用A a(“^_^") 或者A c="^_^" 时会发生一些意想不到的行为,所以很多时候我们需要禁用这样的用法. 一种方法就是把拷贝构造函数和赋值操作符显式的定义为private,但是这样需要很多代码. 于是boost库为大家提供了一个简单的方法:只需要将类继承于noncopyable就可以了. #include "

Boost库编译安装

一.Boost库介绍         Boost库是一个经过千锤百炼.可移植.提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一.Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容.在C++社区中影响甚大,其成员已近2000人. Boost库为我们带来了最新.最酷.最实用的技术,是不折不扣的“准”标准库. Boost库中比较有名的几个库: (1)Regex,正则表达式库: (2)Spirit,LL parser framework,用C

在VS2013中使用boost库遇到的问题及解决(转)

原文转自 https://my.oschina.net/SunLightJuly/blog/676891?p=1 最近的项目需要集成一个使用了boost库的开源库.原本应该是比较简单的工作,因为使用的是VS2013,而boost库是最新下载的1.60.0版本(注:写这篇文章时1.61.0刚好release),结果还是费了一点工夫.现在把它记下来,给自己留个记录备查吧. 经过这么久的发展,boost库其实用起来已经很简单了.首先下载新版本的包.在windows下,用zip格式的包是最方便的.然后随

(九)boost库之文件处理filesystem

(九)boost库之文件处理filesystem filesystem库是一个可移植的文件系统操作库,它在底层做了大量的工作,使用POSIX标准表示文件系统的路径,使C++具有了类似脚本语言的功能,可以跨平台操作目录.文件,写出通用的脚本程序. 1.path的构造函数可以接受C字符串和string,也可以是一个指定首末迭代器字符串序列区间. 2.filesystem提供了一系列的文件名(或目录)检查函数. 3.有丰富的函数用于获取文件名.目录名.判断文件属性等等. 4.filesystem库使用