zoukankan      html  css  js  c++  java
  • 通过迷宫问题归纳回溯法

    回溯法,是一种常用的枚举求解子空间的一种思想。在搜索过程中尝试找到问题的解。如果将每个状态空间看作是一个结点,则回溯查找解路径的过程有点类似于图或者树的深度优先遍历。当未达到终点时,一直往下遍历,如果遇到这条路径无解,则回溯到上一个可行结点,再往其他方向搜索。

    方法:联想到二叉树的深度优先遍历,可以规划成递归的形式,或者用保存求解路径。

     下面通过一个迷宫寻路问题来归纳出比较通用的回溯法的步骤。

    迷宫寻路问题:问题:给定一个迷宫,找到从入口到出口的所有可行路径,并给出其中最短的路径

     分析:用二维数组来表示迷宫,则走迷宫问题用回溯法解决的的思想类似于图的深度遍历。从入口开始,选择下一个可以走的位置,如果位置可走,则继续往前,如果位置不可走,则返回上一个位置,重新选择另一个位置作为下一步位置。

            N表示迷宫的大小,使用Maze[N][N]表示迷宫,值为0表示通道(可走),值为1表示不可走(墙或者已走过);

            Point结构体用来记录路径中每一步的坐标(x,y)

           (ENTER_X,ENTER_Y) 是迷宫入口的坐标

           (EXIT_X, EXIT _Y)    是迷宫出口的坐标

           Path容器用来存放一条从入口到出口的通路路径

           BestPath用来存放所有路径中最短的那条路径

    
    
      1 #include <iostream>  
      2 #include <vector>  
      3    
      4 using namespace std;  
      5    
      6 typedef struct  
      7 {  
      8     int x;  
      9     int y;  
     10 }Point;  
     11    
     12 #define N 10         //迷宫的大小  
     13 #define ENTER_X 0    //入口的位置(0,0)  
     14 #define ENTER_Y 0  
     15 #define EXIT_X N-1   //出口的位置(N-1,N-1)  
     16 #define EXIT_Y N-1   
     17    
     18    
     19 int Maze[N][N]//定义一个迷宫,0表示通道,1表示不可走(墙或已走)  
     20 int paths;     //路径条数  
     21 vector<Point> Path;//保存一条可通的路径  
     22 vector<Point> BestPath;//保存最短的路径  
     23    
     24    
     25 //初始化迷宫  
     26 void InitMaze()  
     27 {  
     28 <span style="white-space:pre">  </span>//简单起见,本题定义一个固定大小10*10的迷宫  
     29 <span style="white-space:pre">  </span>//定义一个迷宫,0表示通道,1表示墙(或不可走)  
     30     int mz[10][10]={  
     31     {0,0,1,1,1,1,1,1,1,1}, //0  
     32     {1,0,0,1,1,0,0,1,0,1}, //1  
     33     {1,0,0,1,0,0,0,1,0,1}, //2  
     34     {1,0,0,0,0,1,1,0,0,1}, //3  
     35     {1,0,1,1,1,0,0,0,0,1}, //4  
     36     {1,0,0,0,1,0,0,0,0,1}, //5  
     37     {1,0,1,0,0,0,1,0,0,1}, //6  
     38     {1,0,1,1,1,0,1,1,0,1}, //7  
     39     {1,1,0,0,0,0,0,0,0,0}, //8  
     40     {1,1,1,1,1,1,1,1,1,0}  //9  
     41     //   0 1 2 3 4 5 6 7 8 9  
     42     };   
     43    
     44     //复制到迷宫  
     45     memcpy(Maze,mz,sizeof(mz));  
     46    
     47     paths = 0;  
     48 }  
     49    
     50 //从(x,y)位置开始走;初始为(0,0)  
     51 bool MazeTrack(int x,int y)  
     52 {  
     53     ///////////////////////////////////////  
     54     //当前点加入到路径  
     55     bool hasPath = false;
     56     Point p={x,y};  
     57     
     58     if ( x < N && x>=0 && y<N && y>0 && Maze[x][y]==0)
     59     {    Path.push_back(p);  
     60         Maze[x][y] = 1;         //设置为已走,不可走  
     61      
     62     //cout<<"来到("<<x<<","<<y<<")"<<endl;    
     63     
     64     //如果该位置是出口,输出结果  
     65         if(x == EXIT_X && y== EXIT_Y)  
     66         {  
     67         cout<<"找到一条道路"<<endl;  
     68         paths++;  
     69         hasPath = true;
     70         
     71           
     72         //输出路径  
     73         vector<Point>::iterator it;  
     74         for(it=Path.begin();it!=Path.end();++it)  
     75         {  
     76             cout<<"("<<it->x<<","<<it->y<<") ";  
     77         }  
     78         cout<<endl;  
     79    
     80         //判断是否更优  
     81         if(BestPath.size()==0)//如果是找到的第一条路径,直接复制到最优路径  
     82         {  
     83             for(it=Path.begin();it!=Path.end();++it)  
     84             {  
     85                 BestPath.push_back(*it);  
     86             }  
     87 
     88         }  
     89         else //不是第一条,则判断是否更短  
     90         {  
     91             //更短,复制到最优路径  
     92             if(Path.size()<BestPath.size())  
     93             {  
     94                 BestPath.clear();  
     95                 for(it=Path.begin();it!=Path.end();++it)  
     96                 {  
     97                     BestPath.push_back(*it);  
     98                 }  
     99             }  
    100         }
    101         
    102         return hasPath
    103         }  
    104    
    105         ///////////////////////////////////////  
    106         //判断(x,y)位置的上、下、左、右是否可走  
    107         
    108         hasPath =  MazeTrack(x-1,y) || MazeTrack(x+1,y) || MazeTrack(x,y-1) || MazeTrack(x,y+1)
    109        
    110         if (!hasPath)
    111         {
    112             //返回上一步  
    113             Path.pop_back();  
    114             Maze[x][y] = 0;         //设置为未走  
    115         }
    116     
    117     }
    118     return hasPath
    119 
    120 }  
    121    
    122    
    123 int main(int argc, char* argv[])  
    124 {  
    125     //初始化迷宫  
    126     InitMaze();  
    127           
    128 /*  //显示迷宫 
    129     for(int i=0;i<N;++i){ 
    130         for(int j=0;j<N;++j) 
    131             cout<<Maze[i][j]<<"  "; 
    132         cout<<endl; 
    133     }*/  
    134    
    135     //回溯法走迷宫  
    136     MazeTrack(ENTER_X,ENTER_Y);  
    137    
    138     //显示最优的路径  
    139     cout<<"可行路径总条数为"<<paths<<";最优路径为"<<endl;  
    140     vector<Point>::iterator it;  
    141     for(it=BestPath.begin();it!=BestPath.end();++it)  
    142     {  
    143         cout<<"("<<it->x<<","<<it->y<<") ";  
    144     }  
    145     cout<<endl;  
    146     return 0;  
    147 }  
    
    
    
    
    

    总结归纳一下回溯法求解路径的模板,如下:

     1 using namespace std;
     2 #define N 100  
     3 #define M 100
     4 
     5 typedef struct  
     6 {  
     7        int x;  
     8        int y;
     9 }Point; 
    10  
    11 vector<Point>solutionPath ;  //存放有解的坐标路径
    12 
    13 //主函数 x,y默认为起始结点,如(0,0), 得到从起始结点到目的结点的路径。
    14 bool hasSolutionFunction( template<typename T>* Matrix , int x, int y)
    15 {
    16         
    17     bool *visited = new bool[M*N]; 
    18     memset (visited,0,M*N); //visited 存放每个结点是否被遍历,true为已经遍历过,false为否
    19     
    20     res =  hasSolutionCore(Matrix , x ,y)
    21     cout<<solutionPath<<endl;
    22     return res
    23 
    24 }
    25 
    26 //深度遍历求解路径的函数
    27 bool hasSolutionCore(template<typename T>*  Matrix , int x, int y)
    28 {
    29     
    30     hasSolution = false;
    31     Point p = Point(x,y);
    32     
    33 
    34         
    35     if (x,y) is terminal  //x,y 已经是终止条件,当求解到这个结点是叶结点或目的地    
    36         {
    37         solutionPath.push_back(p);
    38         return true;
    39         }
    40 
    41     if ((x,y) && visited[x][y]==flase )// x,y是合法结点(具体条件可扩展),且未被访问过
    42     {
    43         visited[x][y] = true;
    44         solutionPath.push_back(p);
    45         
    46         hasSolution = hasSolutionCore(Matrix,x-1, y) ||hasSolutionCore(Matrix,x,y-1)||... //如果不是叶结点,则该路径是否有解取决于其他方向的往后求解。
    47         
    48         // x,y结点以下的所有子路径都无解,则回溯
    49         if (!hasSolution)
    50         {
    51         visited[x][y] = false;
    52         solutionPath.pop_back();
    53         }
    54         
    55     }
    56     return hasSolution;
    57     
    58 }

    #include <iostream>  #include <vector>     using namespace std;     typedef struct  {      int x;      int y;  }Point;     #define N 10         //迷宫的大小  #define ENTER_X 0    //入口的位置(0,0)  #define ENTER_Y 0  #define EXIT_X N-1   //出口的位置(N-1,N-1)  #define EXIT_Y N-1         int Maze[N][N]//定义一个迷宫,0表示通道,1表示不可走(墙或已走)  int paths;     //路径条数  vector<Point> Path;//保存一条可通的路径  vector<Point> BestPath;//保存最短的路径        //初始化迷宫  void InitMaze()  {  <span style="white-space:pre">  </span>//简单起见,本题定义一个固定大小10*10的迷宫  <span style="white-space:pre">  </span>//定义一个迷宫,0表示通道,1表示墙(或不可走)      int mz[10][10]={      {0,0,1,1,1,1,1,1,1,1}, //0      {1,0,0,1,1,0,0,1,0,1}, //1      {1,0,0,1,0,0,0,1,0,1}, //2      {1,0,0,0,0,1,1,0,0,1}, //3      {1,0,1,1,1,0,0,0,0,1}, //4      {1,0,0,0,1,0,0,0,0,1}, //5      {1,0,1,0,0,0,1,0,0,1}, //6      {1,0,1,1,1,0,1,1,0,1}, //7      {1,1,0,0,0,0,0,0,0,0}, //8      {1,1,1,1,1,1,1,1,1,0}  //9      //   0 1 2 3 4 5 6 7 8 9      };          //复制到迷宫      memcpy(Maze,mz,sizeof(mz));         paths = 0;  }     //从(x,y)位置开始走;初始为(0,0)  bool MazeTrack(int x,int y)  {      ///////////////////////////////////////      //当前点加入到路径  bool hasPath = false;    Point p={x,y};  if ( x < N && x>=0 && y<N && y>0 && Maze[x][y]==0)    {Path.push_back(p);  Maze[x][y] = 1;         //设置为已走,不可走       //cout<<"来到("<<x<<","<<y<<")"<<endl;        //如果该位置是出口,输出结果  if(x == EXIT_X && y== EXIT_Y)  {          cout<<"找到一条道路"<<endl;          paths++;  hasPath = true;                  //输出路径          vector<Point>::iterator it;          for(it=Path.begin();it!=Path.end();++it)          {              cout<<"("<<it->x<<","<<it->y<<") ";          }          cout<<endl;             //判断是否更优          if(BestPath.size()==0)//如果是找到的第一条路径,直接复制到最优路径          {              for(it=Path.begin();it!=Path.end();++it)              {                  BestPath.push_back(*it);              }  
            }          else //不是第一条,则判断是否更短          {              //更短,复制到最优路径              if(Path.size()<BestPath.size())              {                  BestPath.clear();                  for(it=Path.begin();it!=Path.end();++it)                  {                      BestPath.push_back(*it);                  }              }          }return hasPath}     ///////////////////////////////////////  //判断(x,y)位置的上、下、左、右是否可走  hasPath =  MazeTrack(x-1,y) || MazeTrack(x+1,y) || MazeTrack(x,y-1) || MazeTrack(x,y+1)   if (!hasPath){//返回上一步  Path.pop_back();  Maze[x][y] = 0;         //设置为未走  }}return hasPath
    }        int main(int argc, char* argv[])  {      //初始化迷宫      InitMaze();            /*  //显示迷宫     for(int i=0;i<N;++i){         for(int j=0;j<N;++j)             cout<<Maze[i][j]<<"  ";         cout<<endl;     }*/         //回溯法走迷宫      MazeTrack(ENTER_X,ENTER_Y);         //显示最优的路径      cout<<"可行路径总条数为"<<paths<<";最优路径为"<<endl;      vector<Point>::iterator it;      for(it=BestPath.begin();it!=BestPath.end();++it)      {          cout<<"("<<it->x<<","<<it->y<<") ";      }      cout<<endl;      return 0;  }  

  • 相关阅读:
    es5
    总有你用的上插件
    三级联动
    jquery快速入门
    动态创建数据table
    背景裁切
    移动web-bootstrap
    ionic开发之Android可以很快打开主页,iOS要几分钟打开主页
    .Net语言 APP开发平台——Smobiler学习日志:如何在手机上快速实现CandleStickChart控件
    .Net语言 APP开发平台——Smobiler学习日志:如何快速实现Timer计时功能
  • 原文地址:https://www.cnblogs.com/bradleon/p/5936623.html
Copyright © 2011-2022 走看看