迷宫求解3--带环的多出口迷宫求最短路径

假如有以下带环的多出口迷宫地图:
这里写图片描述
这里的思路与之前迷宫求解多出口求最短路径相似,不同的是,这里需要多传一个参数pre,保存当前要落脚的点的上一次走到这个点的大小
1.判定当前点是否能落脚
2.如果能落脚,进行标记,同时将当前点插入到cur_path栈中,更新pre
3.判断是否是出口
a)如果是出口,就比较cur_path与short_path的大小,如果cur_path小就代替short_path
b)如果不是出口,以当前点为准则,采用递归式顺时针继续探测四周
4.如果四周都探测过了,进行回溯
解释:
这里的判断是否能落脚的规则变了:
1.判断当前点是否在地图上,相当于合法判定
2.判定当前点是否是墙
3.如果当前点是1,则可以直接落脚
4.如果当前点已经被标记过了,就比较当前点与pre的大小,当当前点大于pre+1时,就可以落脚,否则不能落脚(结合如下代码看);
这里的标记规则也变了:
首先,入口点的pre规定为(-1,-1),当pre为(-1,-1)时,就标记入口点为2,此后标记规则为,当前落脚点为pre+1;

具体代码实现如下:

 void MazeInit3(Maze* maze){                                                                                 
     if(maze == NULL){
         return;
     }
     int map[MAX_ROW][MAX_COL] = {
         {0,1,0,0,0,0},
         {0,1,1,1,0,0},
         {0,1,0,1,1,1},
         {1,1,1,1,0,0},
         {0,0,1,0,0,0},
         {0,0,1,0,0,0},
     };
     size_t i = 0;
     for(;i<MAX_ROW;i++){
         size_t j = 0;
         for(;j<MAX_COL;j++){
             maze->map[i][j] = map[i][j];
         }
     }
     return;
 }

 int CanStayWithCycle(Maze* maze,Point cur,Point pre){
     if(maze == NULL){
         return 0;
     }
     //当前点是否在地图上
     if(cur.row < 0||cur.col > MAX_COL||cur.row < 0 || cur.row > MAX_ROW){
         return 0;
     }
     int cur_value = maze->map[cur.row][cur.col];
     //当前点是墙
     if(cur_value == 0){
         return 0;
     }
     //当前点是1,就可以以直接落脚
     if(cur_value == 1){
         return 1;
     }
     //当前点如果已经被标记,就比较当前点与pre的大小                                                         
     //a)cur_value 7,pre_value 5 能落脚
     //b)cur_value 6,pre_value 5 不能落脚
     //c)cur_value 5,pre_value 5 不能落脚
     //d)cur_value 4,pre_value 5 不能落脚
     //总结以上情况,当cur_value > pre_value+1时能落脚
     int pre_value = maze->map[pre.row][pre.col];
     if(cur_value > pre_value+1){
         return 1;
     }
     return 0;
 }

 void MarkWithCycle(Maze* maze,Point cur,Point pre){
     if(maze == NULL){
         return;
     }
     if(cur.row < 0 || cur.row >=MAX_ROW || cur.col < 0 || cur.col >= MAX_COL){
         return;
     }
     if(pre.row == -1 && pre.col == -1){
         maze->map[cur.row][cur.col] = 2;
         return;
     }
     int pre_value = maze->map[pre.row][pre.col];
     maze->map[cur.row][cur.col] = pre_value + 1;
     return;
 }

 void _GetShortPathWithCycle(Maze* maze,Point cur,Point pre,Point entry,SeqStack* cur_path,SeqStack* short_path){
     if(maze == NULL){
         return;
     }
     //判断当前点是否能落脚(判定规则变了)
     if(!CanStayWithCycle(maze,cur,pre)){
         return;
     }
     //如果能落脚,就将当前点标记并且插入到cur_path中,更新pre
     MarkWithCycle(maze,cur,pre);
     SeqStackPush(cur_path,cur);
     pre = cur;
     //判断是否是出口
     if(IsEixt(maze,cur,entry)){                                                                             
         //如果是出口,要拿cur_path与short_path进行比较,
         //把比较短的路径保存到short_path中
         if(cur_path->size < short_path->size || short_path->size == 0){
             printf("找到了一条比较短的路径\n");
             SeqStackAssgin(cur_path,short_path);
         }                                                                                                   
         //进行回溯,不管当前找到的这条路径是不是比较短的路径
         SeqStackPop(cur_path);
         return;
     }
     //如果不是出口,以当前为基准,顺时针探测四周
     Point up = cur;
     up.row -= 1;
     _GetShortPathWithCycle(maze,up,pre,entry,cur_path,short_path);

     Point right = cur;
     right.col += 1;
     _GetShortPathWithCycle(maze,right,pre,entry,cur_path,short_path);

     Point down = cur;
     down.row += 1;
     _GetShortPathWithCycle(maze,down,pre,entry,cur_path,short_path);

     Point left = cur;
     left.col -= 1;
     _GetShortPathWithCycle(maze,left,pre,entry,cur_path,short_path);

     //如果四个点都探测过了,进行回溯
     SeqStackPop(cur_path);
     return;
 }

 void GetShortPathWithCycle(Maze* maze,Point entry){
     SeqStack cur_path;
     SeqStack short_path;
     SeqStackInit(&cur_path);
     SeqStackInit(&short_path);
     Point pre = {-1,-1};
        _GetShortPathWithCycle(maze,entry,pre,entry,&cur_path,&short_path);
     SeqStackDebugPrint(&short_path,"最短路径为");
 }

在迷宫求解2中,没有说到,当cur_path小于short_path时,进行替换,这里说一下:
先将short_path中的元素释放掉,在根据cur_path的大小为short_path从新开辟空间,以保证肯定能够存放cur_path的元素,然后循环的将cur_path中的元素拷贝到short_path中即可;
代码如下:

  void SeqStackAssgin(SeqStack* from,SeqStack* to){
      //为了保证to里面的内存能够足够的容纳from中的元素
      //就采用以下的策略:
      //1.释放to中的原有内存
      SeqStackDestroy(to);
      //2.根据from元素的个数,确定内存申请的大小
      //  给to重新申请一个足够的内存
      to->size = from->size;
      to->capacity = from->capacity;
      to->data = (SeqStackType*)malloc(to- >capacity*sizeof(SeqStackType));
      //3.再进行数据的拷贝                                                                                    
      size_t i = 0;
      for(;i<from->size;i++){
          to->data[i] = from->data[i];
      }
      return;
  }
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页