一、问题概述
之前,我们了解了如何实现迷宫问题(对于迷宫只有一个出口可以通的情况),事实上我们的迷宫有多个出口,对于每条路径来说,有长有短,所以在这里,我们讨论一下迷宫的最短路径,即迷宫路径的最优解问题。
二、解决方案
对于这样一个迷宫:
注:数字为0的表示可以通过,数字为1的表示不可以通过。
从入口坐标:(2,0)开始,可以到达出口位置的通路总共有三条。可想而知,肯定得把每一条路径都得遍历一遍,记录每条路径的长度。我们这里采用了递归的思想。
求解最短路径的办法:
(1)将入口点标记起来,给其赋值;
(2)每次访问的下一个位置就是前一个位置的值+1,直至一条路径成功通往出口;
(3)如果访问下一条路径的时候,递归会回退,在这里回退时它还会检测是否有通路,(上上节讲迷宫问题时有具体实现,可以去参照),这时由于我们赋的值已经改变了,所以此时判断的条件为如果它的下一个位置的值+1>当前的位置的值,它就可以通过。
(4)当每条路径走完后,会显示最后出口的值,这样就知道哪条路径最短啦。
图示如下:
三、实现代码
//Maze1.h
#include<iostream>
using namespace std;
#include<assert.h>
#include<stack>
struct Pos
{
int _row;
int _col;
};
void GetMaze(int *Maze,size_t N)
{
FILE* fout = fopen("Maze1.txt","r");
assert(fout);
for(size_t i = 0; i < N; ++i)
{
for(size_t j = 0; j < N; )
{
int value = fgetc(fout);
if(value == '1' || value == '0')
{
Maze[i*N+j] = value - '0';
++j;
}
else if(value == EOF)
{
cout<<"Maze error!"<<endl;
return;
}
}
}
}
bool IsCheckPath(int *maze,size_t n,Pos cur,Pos next)
{
if((next._row < 0 || next._row >= 10)
|| (next._col < 0 || next._col >= 10)
||(maze[next._row*n+next._col] == 1))
{
return false;
}
if(maze[next._row*n+next._col] == 0)
{
return true;
}
return maze[next._row*n+next._col]+1 > maze[cur._row*n+cur._col];
}
//递归
void GetMazePath(int *maze,size_t n,Pos entry,stack<Pos>& s,stack<Pos>& ss)
{
Pos cur;
Pos next;
s.push(entry);
next = entry;
if(entry._row == n-1)
{
if(ss.empty() || s.size() < ss.size())
{
ss = s;
}
s.pop();
return;
}
//探测上下左右
//上
next = entry;
cur = next;
next._row-=1;
if(IsCheckPath(maze,n,cur,next))
{
maze[next._row*n+next._col] = maze[cur._row*n+cur._col]+1;
GetMazePath(maze,n,next,s,ss);
}
//右
next = entry;
cur = next;
next._col+=1;
if(IsCheckPath(maze,n,cur,next))
{
maze[next._row*n+next._col] = maze[cur._row*n+cur._col]+1;
GetMazePath(maze,n,next,s,ss);
}
//下
next = entry;
cur = next;
next._row+=1;
if(IsCheckPath(maze,n,cur,next))
{
maze[next._row*n+next._col] = maze[cur._row*n+cur._col]+1;
GetMazePath(maze,n,next,s,ss);
}
//左
next = entry;
cur = next;
next._col-=1;
if(IsCheckPath(maze,n,cur,next))
{
maze[next._row*n+next._col] = maze[cur._row*n+cur._col]+1;
GetMazePath(maze,n,next,s,ss);
}
//四方都不通
s.pop();
}
void PrintMaze(int *maze,size_t n)
{
cout<<"迷宫显示:>"<<endl;
for(size_t i = 0; i < n; ++i)
{
for(size_t j = 0; j < n; ++j)
{
cout<<maze[i*n+j]<<" ";
}
cout<<endl;
}
}
//Maze1.cpp
#include"Maze1.h"
//用栈和递归实现迷宫问题
const size_t N = 10;
void FunTest()
{
int Maze[N][N];
Pos entry = {2,0};
stack<Pos> ss;
stack<Pos> ss1;
GetMaze((int*)Maze,N);
Maze[entry._row][entry._col] = 2;
GetMazePath((int*)Maze,N,entry,ss,ss1);
cout<<"迷宫是否有出口?"<<!ss.empty()<<endl;
PrintMaze((int*)Maze,N);
}
int main()
{
FunTest();
return 0;
}
四、运行结果