回溯法解迷宫问题

  迷宫问题中,在寻找路径时,采用的方法通常是:从入口出发,沿某一方向向前试探,若能走通,则继续向前进;如果走不通,则要沿原路返回,换一个方向再继续试探,直到所有可能的能跟都试探完成为止。为了保证在任何位置上都能沿原路返回(回溯),要建立一个后进先出的栈来保存从入口到当前位置的路径。

      而且在求解迷宫路径中,所求得的路径必须是简单路径。即在求得的路径上不能有重复的同一块通道。

      为了表示迷宫,设置一个数组,其中每个元素表示一个方块的状态,为0时表示对应方块是通道,为1时表示对应方块为墙,数组如下所示:

[cpp] 
view plain
copy

  1. int mg[10][10] = {      //定义一个迷宫,0表示通道,1表示墙  
  2.     {1,1,1,1,1,1,1,1,1,1},  
  3.     {1,0,0,1,1,0,0,1,0,1},  
  4.     {1,0,0,1,0,0,0,1,0,1},  
  5.     {1,0,0,0,0,1,1,0,0,1},  
  6.     {1,0,1,1,1,0,0,0,0,1},  
  7.     {1,0,0,0,1,0,0,0,0,1},  
  8.     {1,0,1,0,0,0,1,0,0,1},  
  9.     {1,0,1,1,1,0,1,1,0,1},  
  10.     {1,1,0,0,0,0,0,0,0,1},  
  11.     {1,1,1,1,1,1,1,1,1,1}};  

      对于迷宫中每个方块,都有上下左右四个方块相邻,第i行第j列的当前方块的位置为(i,j),规定上方方块为方位0,按顺时针方向递增编号。假设从方位0到方位3的方向查找下一个可走方块。

      为便于回溯,对于可走的方块都要进栈,并试探它的下一个可走方位,将这个可走的方位保存到栈中,栈定义如下:

[cpp] 
view plain
copy

  1. struct St                //定义一个栈,保存路径  
  2. {  
  3.     int i;               //当前方块的行号  
  4.     int j;               //当前广场的列号  
  5.     int di;              //di是下一可走方位的方位号  
  6. } St[MaxSize];           //定义栈  

      求解路径过程为:先将入口进栈(初始方位设置为-1),在栈不为空时循环:取栈顶方块(不退栈),若是出口,则输出栈中方块即为路径。否则,找下一个可走的相邻方块,若不存在这样的方块,则退栈。若存在,即将其方位保存到栈顶元素中,并将这个可走相邻方块进栈(初始方位设置为-1)。

      为保证试探可走相邻方块不是已走路径上的方块,如(i,j)已经进栈,在试探(i+1,j)的下一可走方块时,又试探到(i,j),这样会引起死循环,为此,在一个方块进栈后,将对应的mg数组元素值改为-1(变为不可走),当退栈时(没有可走的相邻方块),将其恢复为0.

      算法如下:

[cpp] 
view plain
copy

  1. #include <iostream>        
  2. #include <iomanip>    
  3. #include <stdlib.h>  
  4. using namespace std;   
  5.   
  6.   
  7. #define MaxSize 100  
  8.   
  9. int mg[10][10] = {      //定义一个迷宫,0表示通道,1表示墙  
  10.     {1,1,1,1,1,1,1,1,1,1},  
  11.     {1,0,0,1,1,0,0,1,0,1},  
  12.     {1,0,0,1,0,0,0,1,0,1},  
  13.     {1,0,0,0,0,1,1,0,0,1},  
  14.     {1,0,1,1,1,0,0,0,0,1},  
  15.     {1,0,0,0,1,0,0,0,0,1},  
  16.     {1,0,1,0,0,0,1,0,0,1},  
  17.     {1,0,1,1,1,0,1,1,0,1},  
  18.     {1,1,0,0,0,0,0,0,0,1},  
  19.     {1,1,1,1,1,1,1,1,1,1}};  
  20.   
  21. struct St                //定义一个栈,保存路径  
  22. {  
  23.     int i;               //当前方块的行号  
  24.     int j;               //当前广场的列号  
  25.     int di;              //di是下一可走方位的方位号  
  26. } St[MaxSize];           //定义栈  
  27.   
  28. int top = -1;            //初始化栈指针  
  29.   
  30. void MgPath(int xi, int yi, int xe, int ye)            //路径为从(xi,yi)到(xe,ye)  
  31. {  
  32.     int i, j, di, find, k;  
  33.     top++;                                             //初始方块进栈  
  34.     St[top].i = xi;St[top].j = yi;St[top].di = -1;  
  35.     mg[xi][yi] = -1;  
  36.     while(top>-1)                                      //栈不为空时循环  
  37.     {  
  38.         i = St[top].i;j = St[top].j;di = St[top].di;  
  39.         if(i==xe && j==ye)                             //找到了出口,输出路径  
  40.         {  
  41.             cout << “迷宫路径如下:/n”;  
  42.             for(k=0; k<=top; k++)  
  43.             {  
  44.                 cout << “/t(“ << St[k].i << “,” << St[k].j << “)”;  
  45.                 if((k+1)%5==0) cout << endl;            //每输出五个方块后换一行  
  46.             }  
  47.             cout << endl;  
  48.             return;  
  49.         }  
  50.         find = 0;  
  51.         while(di<4 && find==0)                          //找下一个可走方块  
  52.         {  
  53.             di++;  
  54.             switch(di)  
  55.             {  
  56.             case 0:i = St[top].i-1; j = St[top].j; break;  
  57.             case 1:i = St[top].i; j = St[top].j+1; break;  
  58.             case 2:i = St[top].i+1; j = St[top].j; break;  
  59.             case 3:i = St[top].i; j = St[top].j-1; break;  
  60.             }  
  61.             if(mg[i][j]==0) find = 1;                      //找到通路  
  62.         }  
  63.         if(find==1)                                        //找到了下一个可走方块  
  64.         {  
  65.             St[top].di = di;                               //修改原栈顶元素的di值  
  66.             top++;                                         //下一个可走方块进栈  
  67.             St[top].i = i; St[top].j = j; St[top].di = -1;  
  68.             mg[i][j] = -1;                                 //避免重复走到这个方块  
  69.         }  
  70.         else                                               //没有路可走,则退栈  
  71.         {  
  72.             mg[St[top].i][St[top].j] = 0;                  //让该位置变成其它路径可走方块  
  73.             top–;  
  74.         }  
  75.     }  
  76.     cout << “没有可走路径!/n”;  
  77. }  
  78.   
  79. int main()  
  80. {  
  81.     MgPath(1,1,8,8);  
  82. }  
    原文作者:回溯法
    原文地址: https://blog.csdn.net/judyge/article/details/45007357
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞