迷宫最短路径求解

来源:互联网 发布:苹果智能拨号软件 编辑:程序博客网 时间:2024/04/29 22:59

上节中只是提到了如何找到迷宫的通路,但是很显然有些迷宫不止一条通路,所以怎样才能求得迷宫最短路径呢?


要找到最短路径,那必然需要知道所有的路径,才能找出最短路径。所以最重要的还是利用栈和回溯法,同时和递归结合起来。

思路:首先从入口点开始,查找下一个结点的时候要与当前结点进行比较,因为所有路过的结点都是被标记的,表示的是从入口点到当前点所走的长度,而且都是递增。

所以有可能被比较的对象是已经被标记过的。理论上已经标记的点如果值小于当前点的值就不能在访问,因为表示形成环了,而且当前的路径更长,没有必要在进行下去。要进行回溯。不过要注意判断的临界点。

每找到一个合法的位置,就将该位置的数据压栈并且标记起来,递归调用找到通路每次都会加1,所以每条找到的通路的标记都会是连续的。如下图,是没有回溯的路径。



第一条路径找完之后回溯找其他路径,从19一直回溯到15,记得出栈,再访问15的左侧(其他方向已被访问过),有通路且没有被标记,则压栈一直走,遇到8,是被访问过的,形成了环且小于17,不值得继续探寻,进行出栈、回溯到8。


8的上方已经被访问过了,继续访问8的右侧,与标记过的值进行比较,小于17,则可以继续访问并重新标记,到11的时候访问它的上方,和之前的动作一样,判断标记,或者回溯回来,直到走到出口处。


运行的结果


继续进行回溯,从8的下方开始,一直回退到入口点,没有其他路径,则栈为空,则调用结束。

期间,需要将路径保存在两个栈中,一个用来保存最短路径,并且及时更新。

代码:

//位置是否合法bool CheckAccess(Pos next, Pos cur){if ((next._row >= 0 && next._row < M)&&(next._col >= 0 && next._col <= N)){if (_maze[next._row][next._col] == 0){return true;}else if (_maze[next._row][next._col] == 1){return false;}else{//当前位置的值与下一个位置的值比较,以防被标记过return _maze[next._row][next._col] > _maze[cur._row][cur._col]+1;}}else{return false;}}void GetShortPath(Pos entry,stack<Pos>& path, stack<Pos>& shortPath){Pos cur = entry;path.push(cur);// 已经找到出口if (entry._row == N-1){//每找到一次路径就打印一次Print();//保存最短路径if (shortPath.empty() || path.size() < shortPath.size()){shortPath = path;}}Pos next = cur;// 上next._row -= 1;if (CheckAccess(next, cur)){// 子问题_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;GetShortPath(next, path, shortPath);}// 右next = cur;next._col += 1;if (CheckAccess(next, cur)){_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;GetShortPath(next, path, shortPath);}// 下next = cur;next._row += 1;if (CheckAccess(next, cur)){_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;GetShortPath(next, path, shortPath);}// 左next = cur;next._col -= 1;if (CheckAccess(next, cur)){_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;GetShortPath(next, path, shortPath);}path.pop();}
测试代码:
stack<Maze<10, 10>::Pos> path, shortPath;m.GetShortPath(entry, path, shortPath);


原创粉丝点击