迷宫问题

迷宫最优解问题:

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

文件如图:

wKiom1cSCnTB8pO4AAAZiAM5LuE146.png

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

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

定义行列范围

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

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

  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,继续回溯查找通路,如果又一次找到通路,就将该栈的长度与最小栈进行比较,如果该栈长度比最小栈还要小,就将它再一次赋给最小栈(保证最小栈是最短的通路),继续回溯,直到整个栈为空,回到了入口,程序结束。

  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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值