迷宫问题

来源:互联网 发布:血液问题人数调查数据 编辑:程序博客网 时间:2024/06/04 01:02

迷宫最优解问题:

迷宫地形我们可以通过读文件的形式,通过已知入口逐个遍历坐标寻找通路。

文件如图:

wKiom1cSCnTB8pO4AAAZiAM5LuE146.png

每个坐标的位置用结构体来记录:

  1. struct Pos    //位置坐标  
  2. {  
  3.    int  _row;  
  4.    int _col;  
  5. };  

定义行列范围

  1. #define M 10   //行  
  2. #define N 10   //列  

初始化迷宫数组
将通过读文件的方式获取的字符转成整型数据,保存在M行N列的数组中。

[cpp] view plain copy
  1. void InitMaze(int* maze)  
  2. {     
  3.     struct WavHeadhWAV;  
  4.     FILE* fout = fopen("MazeMap.txt""r");   // .txt文件要放在当前目录下  
  5.     if (fout == NULL)                       // 这里一定要检查读文件是否成功  
  6.     {  
  7.         cout << "can't find MazeMap.txt !" << endl<<endl;  
  8.         return;  
  9.     }  
  10.     for (int i = 0; i < M; i++)  
  11.     {  
  12.         for (int j = 0; j < N;)  
  13.         {  
  14.             char ch = fgetc(fout);  
  15.             if (ch=='1'||ch=='0')  
  16.             {  
  17.                 maze[i*N + j] = ch - '0';  
  18.                 j++;  
  19.             }  
  20.         }  
  21.     }  
  22.     fclose(fout);  
  23. }  

回溯查找通路

利用栈来存储通路,通过上下左右四个方向依次遍历,如果该位置满足条件,就将它入栈,并将该位置的数据置为2;如果四个方向都不满足条件就执行出栈操作,回溯查找满足条件的位置(这时候如果栈为空了,说明查找通路失败),继续循环遍历,直到找到出口为止。

这里建立一个最小栈,如果找到出路,就将该栈赋给最小栈,并将出口置为1,继续回溯查找通路,如果又一次找到通路,就将该栈的长度与最小栈进行比较,如果该栈长度比最小栈还要小,就将它再一次赋给最小栈(保证最小栈是最短的通路),继续回溯,直到整个栈为空,回到了入口,程序结束。

[cpp] view plain copy
  1. bool SearchMazePath(int *maze, Pos entry, stack<Pos>& paths)   // 利用栈回溯查找通路,并实现迷宫的最优解  
  2. {  
  3.     assert(maze);  
  4.     stack<Pos>min;  
  5.     paths.push(entry);  
  6.     while (!paths.empty())  
  7.     {  
  8.         Pos cur = paths.top();  
  9.         maze[cur._row*N+cur._col] = 2;  
  10.         if (cur._row==M-1)  
  11.         {  
  12.             if (paths.size()< min.size() || min.size() == 0)  
  13.             {  
  14.                 min = paths;  
  15.             }  
  16.             paths.pop();  
  17.             maze[min.top()._row*N + min.top()._col] = 1;  
  18.         }     
  19.         Pos next = cur;  
  20.         next._col--;  //左  
  21.         if (CheckIsAccess(maze, next))  
  22.         {  
  23.             paths.push(next);  
  24.             maze[next._row*N + next._col] = 2;  
  25.             continue;  
  26.         }  
  27.         next = cur;  
  28.         next._col++; //右  
  29.         if (CheckIsAccess(maze, next))  
  30.         {  
  31.             paths.push(next);  
  32.             maze[next._row*N + next._col] = 2;  
  33.             continue;  
  34.         }  
  35.         next = cur;  
  36.         next._row--; //上  
  37.         if (CheckIsAccess(maze, next))  
  38.         {  
  39.             paths.push(next);  
  40.             maze[next._row*N + next._col] = 2;  
  41.             continue;  
  42.         }  
  43.         next = cur;  
  44.         next._row++; //下  
  45.         if (CheckIsAccess(maze, next))  
  46.         {  
  47.             paths.push(next);  
  48.             maze[next._row*N + next._col] = 2;  
  49.             continue;  
  50.         }  
  51.         paths.pop();  
  52.     }  
  53.     if (paths.empty()&&!min.empty())  
  54.     {  
  55.             maze[min.top()._row*N + min.top()._col] = 2;  
  56.             return true;  
  57.     }  
  58.     return false;  
  59. }  

检查该位置是否合法:(坐标在行列范围之内)

  1. bool CheckIsAccess(int* maze, const Pos& next)    // 检查该位置是否合法  
  2. {  
  3.     assert(maze);  
  4.     if ((next._row >= 0 && next._row <= N) && (next._col >= 0 && next._col < M) && maze[next._row*N + next._col] == 0)  
  5.     {  
  6.         return true;  
  7.     }  
  8.     return false;  
  9. }  

打印迷宫:

  1. void PrintMaze(int *maze)   // 打印迷宫  
  2. {  
  3.     assert(maze);  
  4.     for (int i = 0; i < M; i++)  
  5.     {   
  6.         for (int j = 0; j < N; j++)  
  7.         {  
  8.             cout << maze[i*N + j] <<" " ;  
  9.         }  
  10.         cout << endl;  
  11.     }  
  12.     cout << endl;    
  13. }  

wKioL1cSXnWRU9roAAAG8lMrhuE483.png


下面简单阐述下使用栈(循环)和使用递归来走迷宫的区别:

使用递归:
分为两个部分:
一部分为已走过的路径(通路)
另一问题是:递归的子问题(根据下一个可以通的位置继续查找出口)。
将走过的路径保存在栈帧内。
递归结束时返回上一层栈帧,销毁当前栈帧。

使用栈(保存走过的路径)
分为两个部分:
一部分为已走过的路径(通路),将其保存在栈内
另一部分为:
试探四个方向,沿着某个可以走通的方向一直试探下去,直到走不通时,退出栈顶元素,栈顶元素始终为当前所处的位置。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;#include<cassert>struct Pos//设置坐标{    Pos(int x, int y)    :_x(x)    , _y(y)    {}    int _x;    int _y;};template<size_t M,size_t N>class Maze{public:    Maze(int **arr, FILE* fp)//构造迷宫        :_row(M)        , _col(N)        , _maze(arr)    {        int ch = 0;        assert(fp);        for (size_t i = 0; i < _row; ++i)//从文件中读取迷宫        {            for (size_t j = 0; j < _col;)            {                char ch = fgetc(fp);                if (ch == '0' || ch == '1')                {                    _maze[i][j] = ch - '0';                    ++j;                }            }        }        fclose(fp);    }    bool PassMaze(Pos Entry)    {        //递归算法        Pos cur = Entry;        Pos next = cur;        _maze[next._x][next._y] = 2;//将走过的路进行标记        //判断是否为出口        if (next._x == N - 1)        {            return true;        }        //向上查探        next._x -= 1;        if (_CheckAccess(next))        {            if (PassMaze(next))            {                return true;            }        }        //向右查探        next = cur;        next._y += 1;        if (_CheckAccess(next))        {            if (PassMaze(next))            {                return true;            }        }        //向下查探        next = cur;        next._x += 1;        if (_CheckAccess(next))        {            if (PassMaze(next))            {                return true;            }        }        //向左查探        next = cur;        next._y -= 1;        if (_CheckAccess(next))        {            if (PassMaze(next))            {                return true;            }        }        //走到死胡同时标记为3        _maze[cur._x][cur._y] = 3;        return false;    }    ~Maze()    {        for (int i = 0; i <_row; ++i)        {            delete[] _maze[i];        }        delete[] _maze;    }    friend ostream& operator<<(ostream& out, Maze& m);protected:    bool _CheckAccess(Pos cur)    {        if (cur._x >= 0 && cur._x < N && cur._y >= 0 && cur._y < N && _maze[cur._x][cur._y] == 1)        {            return true;        }        return false;    }private:    int** _maze;    int _row;    int _col;}; ostream& operator<<(ostream& out, Maze<10,10>& m){     for (int i = 0; i < m._row; ++i)     {         for (int j = 0; j < m._col; ++j)         {             out << m._maze[i][j] << "  ";         }         cout << endl;     }     return out;}
测试代码:

void Test(){    FILE* fp = fopen("Maze.txt", "r");    int row = 0;    int col = 0;    fscanf(fp, "%d %d", &row, &col);    int Start_x = 0;    int Start_y = 0;    fscanf(fp, "%d %d", &Start_x, &Start_y);    //动态开辟二维数组    int **arr = new int*[row];    for (int i = 0; i < col; ++i)    {        arr[i] = new int[col];    }    Maze<10,10> maze(arr,fp);//初始化迷宫    cout << maze << endl;    cout << maze.PassMaze(Pos(Start_x, Start_y)) << endl;    cout << maze << endl;    fclose(fp);}int main(){    Test();    return 0;}
2.非递归走迷宫(利用栈来保存迷宫的路径)

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;#include<cassert>#include<stack>struct Pos//设置坐标{    Pos(int x, int y)    :_x(x)    , _y(y)    {}    int _x;    int _y;};template<size_t M,size_t N>class Maze{public:    Maze(int **arr, FILE* fp)//构造迷宫        :_row(M)        , _col(N)        , _maze(arr)    {        int ch = 0;        assert(fp);        for (size_t i = 0; i < _row; ++i)//从文件中读取迷宫        {            for (size_t j = 0; j < _col;)            {                char ch = fgetc(fp);                if (ch == '0' || ch == '1')                {                    _maze[i][j] = ch - '0';                    ++j;                }            }        }        fclose(fp);    }    //使用循环    bool PassMaze(Pos Entry)    {        stack<Pos > s;        s.push(Entry);        _maze[Entry._x][Entry._y] = 2;        while (!s.empty())        {            Pos cur = s.top();            _maze[cur._x][cur._y] = 2;            if (cur._x == N - 1)            {                return true;            }            //向上查探            Pos next = cur;            next._x -= 1;            if (_CheckAccess(next))            {                s.push(next);                continue;            }            //向右查探            next = cur;            next._y += 1;            if (_CheckAccess(next))            {                s.push(next);                continue;            }            //向下查探            next = cur;            next._x += 1;            if (_CheckAccess(next))            {                s.push(next);                continue;            }            //向左查探            next = cur;            next._y -= 1;            if (_CheckAccess(next))            {                s.push(next);                continue;            }            s.pop();            _maze[cur._x][cur._y] = 3;        }        return false;    }    ~Maze()    {        for (int i = 0; i <_row; ++i)        {            delete[] _maze[i];        }        delete[] _maze;    }    friend ostream& operator<<(ostream& out, Maze& m);protected:    bool _CheckAccess(Pos cur)    {        if (cur._x >= 0 && cur._x < N && cur._y >= 0 && cur._y < N && _maze[cur._x][cur._y] == 1)        {            return true;        }        return false;    }private:    int** _maze;    int _row;    int _col;}; ostream& operator<<(ostream& out, Maze<10,10>& m){     for (int i = 0; i < m._row; ++i)     {         for (int j = 0; j < m._col; ++j)         {             out << m._maze[i][j] << "  ";         }         cout << endl;     }     return out;}
测试代码如下:
void Test(){    FILE* fp = fopen("Maze.txt", "r");    int row = 0;    int col = 0;    fscanf(fp, "%d %d", &row, &col);    int Start_x = 0;    int Start_y = 0;    fscanf(fp, "%d %d", &Start_x, &Start_y);    //动态开辟二维数组    int **arr = new int*[row];    for (int i = 0; i < col; ++i)    {        arr[i] = new int[col];    }    Maze<10,10> maze(arr,fp);//初始化迷宫    cout << maze << endl;    cout << maze.PassMaze(Pos(Start_x, Start_y)) << endl;    cout << maze << endl;    fclose(fp);}int main(){    Test();    return 0;}



原创粉丝点击