1. 多通路迷宫初始化
先构建一个多通路迷宫,并且对其初始化
void MazeInitShortPath(Maze* maze)
{if(maze == NULL){return;}int row = 0;int col = 0;for(; row < MAX_COL; row++){for(col = 0; col < MAX_COL; col++){maze -> map[row][col] = Map[row][col];}printf("\n");}
}
2. 定义一个栈并且打印
/** * @brief* * @用来测试迷宫栈* @param msg */
void SeqStackDebugPrint(SeqStack* short_path, char* msg)
{printf("[%s]\n", msg);if(short_path == NULL || msg == NULL){return;}int i =0;for(;i < short_path -> size; i++){printf("(%d, %d)\n", short_path -> data[i].row, short_path -> data[i].col);}printf("\n");
}
3. 递归找通路
在次过程中, 用到的思路和上一篇的迷宫求通路的思路一样. 即就是利用递归的方式实现.不过因为此次有好多个出口, 所以我们每次都需要定义两个栈, 保存当前路径, 以及最短路径, 最后将最短路径中的内容打印出来.首先, 先判断当前点是否可以落脚, 如果不能落脚, 就直接退出, 如果可以落脚, 就现将当前位置标记, 然后将其入栈, 再判断当前位置是否是出口, 如果是出口就得判断当前栈和最短路径栈中它们两个哪个路径短, 如果当前路径比最短路径的步数少, 或者最短;路径栈为空, 就用当前栈代替保存最短路径的那个栈, 同时需要进行回溯, 将保存当前路径的栈出栈.如果当前位置不是出口, 就对当前位置周围的四个位置进行探索,直到找到出口为止. 如果当前位置周围的四个点都已经探索, 此时就需要回溯了, 回溯的过程中也需要将保存当前位置的栈的元素出栈.
//辅助递归
void _GetShortPath(Maze* maze, Point cur, Point entry, SeqStack* cur_path, SeqStack* short_path)
{if(maze == NULL){return;}printf("(%d, %d)\n", cur.row, cur.col);//1. 判断当前是否可以落脚if(CanStay(maze, cur) == 0){return;}//2. 能落脚就将其标记, 插入到cur_pathMark(maze, cur);SeqStackPush(cur_path, cur);//3. 判定当前是否是出口//b) 如果当前路径没有short_path短, 就回溯找其他路径, 在回溯前也需要将 cur_path 出栈if(IsExit(maze, cur, entry)){printf("找到了一条较短的路\n");if(cur_path -> size < short_path -> size || short_path -> size == 0){//a) 如果是出口, 说明找到了一条路, 拿着当路径和short_path 比较, 如果当前路径比 short_path 路径短, //应当前路径代替 short_path(打擂台), 或者 short_path 是个空栈, 就用当前栈代替short_path, 代替完//需要回溯, 找其他路径SeqStackAssgin(short_path, cur_path);}SeqStackPop(cur_path);return;}//4. 当前点不是出口, 尝试找四个方向(探测四个方向)Point up = cur;up.row -= 1;_GetShortPath(maze, up, entry, cur_path, short_path);Point right = cur;right.col += 1;_GetShortPath(maze, right, entry, cur_path, short_path);Point down = cur;down.row += 1;_GetShortPath(maze, down, entry, cur_path, short_path);Point left = cur;left.col -= 1;_GetShortPath(maze, left, entry, cur_path, short_path);//5. 如果四个方向都探测过了, 回溯返回到上一个点, 同时 cur_path 出栈 SeqStackPop(cur_path);
}
void GetShortPath(Maze* maze, Point entry)
{if(maze == NULL){return;}if(entry.row < 0 || entry.row >= MAX_ROW || entry.col < 0 || entry.col >= MAX_COL){return;}SeqStack cur_path;SeqStack short_path;SeqStackInit(&cur_path);SeqStackInit(&short_path);_GetShortPath(maze, entry, entry, &cur_path, &short_path);SeqStackDebugPrint(&short_path, "打印栈内容");printf("%d\n", short_path.size);
}
4. 栈的复制
为了代码实现的简单, 我们定义两个栈, from, to, from比to的元素要少. 在复制之前, 将to 的内存先进行释放, 然后对to进行动态内存分配, 接着将 from 结构体的所有信息全部复制到 to 中,最后将from中的元素依次复制给 to即可
void SeqStackAssgin(SeqStack* to, SeqStack* from)
{if(from == NULL || to == NULL){return;}SeqStackDestroy(to);to -> data = (Point*)malloc(from -> capacity * sizeof(SeqStackType));to -> size = from -> size;int i = 0;for(; i < from -> size; i++){to -> data[i] = from -> data[i];}
}
5. 总结
总结一下, 整体思路如下. 先定义两个栈 cur_path , shrott_path, 前者保存当前路径.后者保存最短路径, 接着 判断当前位置是否可以落脚, 如果不能落脚就直接返回, 如果可以落脚就将当前位置标记, 然后将当前点进行入栈, 入栈到 cur_path中, 接下来判断当前位置是否为出口, 如果是出口, 就比较 cur_path 和 short_path 之间的长度, 如果 cur_path的元素少于 short_path 的元素或者 short_path 为空, 就用cur_path 代替 short_path, 然后将当前 cur_path 栈出栈, 接着进行回溯. 如果当前栈的元素个数大于 short_path栈的元素, 就将 cur_path 出栈, 然后进行回溯; 如果当前位置不是出口, 就按照顺序(顺时针)探测当前位置周围的四个点, 如果当前位置周围的四个点都已经探测, 此时说明进入了死胡同, 就需要回溯, 回溯之前不要忘记将当前的栈 cur_path 进行出栈, 最后,当递归结束时, 打印 short_path栈, 因为该栈里保存的就是最短路径