假定迷宫如下:1代表墙,0代表道路,起点在(1,1),终点(11,9)(PS:下标从0开始计算)。
现在寻求一条路径能从起点到达终点(非最短)。
有两种解法:递归与非递归。
递归算法思路:
要用递归,就要寻找一个子问题,该子问题是递归的。很明显,这道题的子问题就是从8个方向(上下左右还有四个斜角)中寻找一个可行方向并向前走一步,该子问题(seekPath函数)的实现代码如下:
struct offset{ int x; int y; }; offset move[]={{-,},{-,},{,},{,},{,},{,-},{,-},{-,-}};//8个不同行动方向下的x和y偏移量 ][]={};//将数组所有节点访问位置0(未访问) ]={ ", ", ", ", ", ", ", ", ", ", ", " };//迷宫数组 list<offset> s;//存放成功路径 int seekPath(int x,int y){//行动一步 int next_x,next_y; &&y==) ;//找到出口 ;i<;i++){//朝8个方向试探下一步 next_x=move[i].x+x; next_y=move[i].y+y; &&a[next_x][next_y]=='){//下一步未走过并且是道路 mark[next_x][next_y]=;//标记该点已经走过 if(seekPath(next_x,next_y)){ offset a={next_x,next_y}; s.push_front(a); //记录正确路径 ; } } } &&y==){//死迷宫 cout<<"failed"<<endl; } ; }
递归过程中,在每个点上有8个方向,在某个方向上若能满足“该方向点未走过并且是道路 ”的条件,即可执行下一步(下一步的方向从第一个方向重新开始计算),直到找到递归出口。递归出口自然是行走到终点的情况。
测试代码如下:
int main(){//测试代码 mark[][]=; ,)) s.push_front(offset{,}); list<offset>::iterator it=s.begin(); while(it!=s.end()){ cout<<"("<<it->x<<","<<it->y<<")"; it++; } ; }
非递归算法思路:
我们首先需要一个辅助链表,链表的作用是为了记录正确路径。从起点开始,有8个方向,若能满足“该方向点未走过并且是道路 ”的条件,即可将该点放入表尾并执行下一步(下一步的方向从第一个方向重新开始计算),当8个方向都不能满足条件时,将该点从表尾删除并回退到上一个点。实现代码如下:
#include <iostream> #include <list> using namespace std; struct offset{ int x; int y; }; struct point{ int x; int y; }; offset move[]={{-,},{-,},{,},{,},{,},{,-},{,-},{-,-}};//8个不同行动方向下的x和y偏移量 ][]={};//将数组所有节点访问位置0(未访问) ]={ ", ", ", ", ", ", ", ", ", ", ", " };//迷宫数组 int main(){//测试代码 mark[][]=; list<point> lists;//存放路径 point s={,}; lists.push_back(s); while(!lists.empty()){ s=lists.back(); ;d<;d++){//朝8个方向试探下一步 int x=s.x+move[d].x; int y=s.y+move[d].y; &&y==){//找到出口 s.x=x; s.y=y; lists.push_back(s); goto end; } ){//下一步未走过并且是道路 mark[x][y]=; point temp={x,y}; lists.push_back(temp); s.x=x; s.y=y; d=; } } lists.pop_back();//删除不可达路径 } cout<<"failed"; end:list<point>::iterator it=lists.begin(); while(it!=lists.end()){ cout<<"("<<it->x<<","<<it->y<<")"; it++; } ; }