您的位置:首页 > 其它

关于迷宫求解及其最优解的问题

2017-10-08 11:39 369 查看
关于迷宫问题,求解它的最优解的问题可以使用栈的概念来实现。简单的迷宫如下图



其中0表示可以走,1表示不能走,显然可见,若是以(3,1)点为入口,则有两个出口分别是(10,3)和(10, 8)。而两个出口的路径长度是不同的。这就产生了迷宫最优解的问题。



下面附上代码,我们寻找下一个位置是否可走的顺序是顺时针顺序,即上右下左。

#pragma once
#include<iostream>
using namespace std;

//#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

#include<assert.h>
#include<stdio.h>
#include<stack>

struct Pos
{
int _row;
int _col;
};

template<size_t M,size_t N>
class Maze
{
public:
Maze()
{
FILE* fout = fopen("MazeMap.txt", "r");
assert(fout);

for (size_t i = 0; i < M; ++i)
{
for (size_t j = 0; j < N;)
{
char ch = fgetc(fout);
if (ch == '1' || ch == '0')
//构建一个以文字内数字为元素的二维数组,1表示不可走,0表示可走
{
_maze[i][j] = ch - '0';
++j;
}
}
}
}

bool CheckAccess(Pos pos)//检查下一个位置是否可以走
{
if ((pos._row<M)&&(pos._col<N)&&(_maze[pos._row][pos._col] == 0))
{
return true;
}
return false;
}

bool GetMazePathR(Pos cur)//递归走
{
_maze[cur._row][cur._col] = 2;//用2表示走过的位置来记录
//找到出口
if (cur._row == M - 1)
{
return true;
}
//探测
Pos next = cur;
//上
next._row -= 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
//右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
//下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
//左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
return false;
}

bool GetMazePathNonR(Pos entry)//非递归走,用回溯的方法
{
stack<Pos> path;
path.push(entry);//先将入口push到栈中
while (!path.empty())
{
Pos cur = path.top();
_maze[cur._row][cur._col] = 2;//用2表示走过的位置来记录
Pos next = cur;
if (cur._row == M-1)
{
return true;
}
//向上探测
--next._row;
if (CheckAccess(next))
{
path.push(next);
continue;
}
next = cur;//如果不能走,让next回到初始的cur的位置

//向右探测
++next._col;
if (CheckAccess(next))
{
path.push(next);
continue;
}
next = cur;

//向下探测
++next._row;
if (CheckAccess(next))
{
path.push(next);
continue;
}
next = cur;

//向左探测
--next._col;
if (CheckAccess(next))
{
path.push(next);
continue;
}
next = cur;

_maze[cur._row][cur._col] = 3;
//如果一个if条件都没有进,那么该位置是死胡同,不能走,用3来表示
path.pop();//将该位置pop出栈
}
return false;
}

bool CheckAccess(Pos cur,Pos next)
//与上一个CheckAccess函数形成重载
{
if ((next._row>=M) || (next._col>=N) )
{
return false;
}
if ((_maze[next._row][next._col] == 0)
|| (_maze[next._row][next._col]> (_maze[cur._row][cur._col] + 1)))
{
return true;
}
return false;
}

void GetMazeShortPathR(Pos cur, stack<Pos>& paths, stack<Pos>& shortpaths)
//求解出口的最短路径
{
paths.push(cur);
//找到出口
if (cur._row == M - 1)
{
if (shortpaths.empty()||(shortpaths.size()>paths.size()))
{
shortpaths = paths;
}
return;
}

//探测
Pos next = cur;

//上
next._row -= 1;
if (CheckAccess(cur,next))
{
_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;
GetMazeShortPathR(next, paths, shortpaths);
}

//右
next = cur
baea
;
next._col += 1;
if (CheckAccess(cur, next))
{
_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;
GetMazeShortPathR(next, paths, shortpaths);
}

//下
next = cur;
next._row += 1;
if (CheckAccess(cur,next))
{
_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;
GetMazeShortPathR(next, paths, shortpaths);
}

//左
next = cur;
next._col -= 1;
if (CheckAccess(cur,next))
{
_maze[next._row][next._col] = _maze[cur._row][cur._col] + 1;
GetMazeShortPathR(next, paths, shortpaths);
}

paths.pop();
}

void Print()
{
for (size_t i = 0; i < M; ++i)
{
for (size_t j = 0; j < N;++j)
{
cout << _maze[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
protected:
int _maze[M]
;
};


三个测试的测试代码及测试结果如下

void TestMaze()
{
Maze<10, 10> m;
m.Print();

Pos entry = {2,0};
stack<Pos> paths, shortpaths;
//cout << "找到出口?" << m.GetMazePathR(entry) << endl;
//cout << "找到出口?" << m.GetMazePathNonR(entry) << endl;
m.GetMazeShortPathR(entry, paths, shortpaths);
m.Print();
}


递归走



非递归走,我们为了突出效果,把(10,8)的出口给封掉,变成不可走



可以看到,以上两种因为查找下一位置的顺序的原因,只找到了一个出口,那么要找出最优的路径,就必须把所有的路径长度求出来进行比较,用3表示满足不了需求,我们可用没走一步就+1的方法来表示。



两条路径的长度分别是9和14,显然9是该迷宫的最优路径,即是最短长度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  迷宫问题