迷宫问题

题目描述


迷宫是一个二维矩阵,其中1为墙,0为路,入口在第一列,出口在最后一列。
要求从入口开始,从出口结束,按照 上,下,左,右 的顺序来搜索路径.并且求出最短路径。

思想


用回溯法,另外递归是天然的回溯法。

下面是具体的实现代码:

#pragma once

#include <iostream>
#include <stack>
using namespace std;

struct Pos
{
    int _row; // 行
    int _col; // 列
};

template<size_t M,size_t N>
class Maze
{
public:
    Maze(int maze[][N])//二维数组传值必须确定列数,因为二维数组在内存中存储时类似一位数组,一行一行存储
    {
        for (size_t i = 0; i < M; ++i)
        {
            for (size_t j = 0; j < N; ++j)
            {
                _maze[i][j] = maze[i][j];
            }
        }
    }

    //Maze(int* maze)
    //{
    //  for (size_t i = 0; i < N; ++i)
    //  {
    //      for (size_t j = 0; j < N; ++j)
    //      {
    //          _maze[i][j] = maze[i*N+j];
    //      }
    //  }
    //}

    void Print()
    {
        for (size_t i = 0;i < M; ++i)
        {
            for (size_t j = 0; j < N; ++j)
            {
                printf("%d  ", _maze[i][j]);
            }
            cout<<endl;
        }
        cout<<endl;
    }

    bool CheckAccess(Pos pos)
    {
        if (pos._row < N && pos._row >= 0
            && pos._col < N && pos._col >= 0
            && _maze[pos._row][pos._col] == 0)
        {
            return true;
        }

        return false;
    }

    // 栈实现
    bool GetPath(Pos entry, stack<Pos>& path)
    {
        path.push(entry);
        while (!path.empty())
        {
            // 1.入口
            // 2.next
            // 3.回溯的上一个位置
            Pos cur = path.top();
            _maze[cur._row][cur._col] = 2;//用2标识走过的路

            // 检查是否已经到出口
            if(cur._row == N-1)
                return true;

            // 探测
            Pos next = cur;
            // 上
            next._row -= 1;
            if (CheckAccess(next))
            {
                path.push(next);
                continue;
            }

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

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

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

            // 四个方向都走不通,回溯
            _maze[cur._row][cur._col] = 3;// 用3标识走不通的路,保证了下次探测时不再走走不通的路
            path.pop();
        }

        return false;
    }

    // 递归实现
    //bool GetPathR(Pos entry, stack<Pos>& path)
    //{
    //  // 返回条件
    //  // 子问题
    //  _maze[entry._row][entry._col] = 2;
    //  if(entry._row == N-1)//返回条件
    //      return true;

    //  Pos next = entry;
    //  // 上
    //  next._row -= 1;
    //  if (CheckAccess(next))
    //  {
    //      if(GetPathR(next, path))
    //          return true;
    //  }

    //  // 下
    //  next = entry;
    //  next._row += 1;
    //  if (CheckAccess(next))
    //  {
    //      if (GetPathR(next, path))
    //      {
    //          return true;
    //      }
    //  }

    //  // 左
    //  next = entry;
    //  next._col -= 1;
    //  if (CheckAccess(next))
    //  {
    //      if (GetPathR(next, path))
    //      {
    //          return true;
    //      }
    //  }

    //  // 右
    //  next = entry;
    //  next._col += 1;
    //  if (CheckAccess(next))
    //  {
    //      if (GetPathR(next, path))
    //      {
    //          return true;
    //      }
    //  }

    //  _maze[entry._row][entry._col] = 3;
    //  return false;
    //}

    bool CheckAccess(Pos cur, Pos next)
    {
        // 1.检查边界 (next._row >= 0 && next._row < N && next._col >= 0 && next._col < N)
        // 2.是否是通路 _maze[next._row][next._col] == 0 
        // 3.是否自己没走过,但是别人走过,解决带环问题 _maze[next._row][next._col] > _maze[cur._row][cur._col]
        if ((next._row >= 0 && next._row < N && next._col >= 0 && next._col < N)
            &&( _maze[next._row][next._col] == 0 || _maze[next._row][next._col] > _maze[cur._row][cur._col]))
        {
            return true;
        }

        return false;
    }

//用递归求最短通路路径
    void GetShortPathR(Pos entry, stack<Pos>& path, stack<Pos>& shortPath)
    {
        // 返回条件
        // 子问题
        if (!path.empty())
        {
            Pos prev = path.top();
            _maze[entry._row][entry._col] = _maze[prev._row][prev._col]+1;
        }

        path.push(entry);
        if(entry._row == N-1)
        {
            if (shortPath.empty()
                || path.size() < shortPath.size())
            {
                Print();
                cout<<"当前路径的长度:"<<path.size()<<endl;
                cout<<"之前最短路径的长度:"<<shortPath.size()<<endl;
                shortPath = path;
            }
        }

        Pos next = entry;
        // 上
        next._row -= 1;
        if (CheckAccess(entry, next))
        {
            GetShortPathR(next, path, shortPath);
        }

        // 右
        next = entry;
        next._col += 1;
        if (CheckAccess(entry, next))
        {
            GetShortPathR(next, path, shortPath);
        }

        // 下
        next = entry;
        next._row += 1;
        if (CheckAccess(entry, next))
        {
            GetShortPathR(next, path, shortPath);
        }


        // 左
        next = entry;
        next._col -= 1;
        if (CheckAccess(entry, next))
        {
            GetShortPathR(next, path, shortPath);
        }

        path.pop();
    }

protected:
    int _maze[M][N];
};

void TestMaze()
{
    const size_t M = 10;
    const size_t N = 10;
    int maze[M][N] = {
    {1,1,1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1,1,1},
    {2,0,0,0,0,0,0,1,1,1},
    {1,1,0,1,1,1,0,1,1,1},
    {1,1,0,0,0,0,0,1,1,1},
    {1,1,1,1,1,0,1,1,1,1},
    {1,1,1,1,1,0,1,1,1,1},
    {1,1,1,1,1,0,1,1,1,1},
    {1,1,1,1,1,0,1,1,1,1},
    {1,1,1,1,1,0,1,1,1,1}
    };

    /*int maze[N][N] = {
        {1,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1},
        {0,0,0,1,1,1,1,1,1,1},
        {1,1,0,1,1,1,1,1,1,1},
        {1,1,0,0,0,0,1,1,1,1},
        {1,1,0,1,1,0,1,1,1,1},
        {1,1,0,1,1,0,0,0,1,1},
        {1,1,0,1,1,0,1,0,1,1},
        {1,1,0,1,1,0,1,1,1,1},
        {1,1,0,1,1,0,1,1,1,1}
    };*/

    Maze<M,N> mz(maze);
    mz.Print();

    Pos entry;
    stack<Pos> path;
    stack<Pos> shortPath;
    entry._row = 2;
    entry._col = 0;
    mz.GetShortPathR(entry, path, shortPath);
    mz.Print();

    while (!shortPath.empty())// 打印最短路径
    {
        Pos pos = shortPath.top();
        printf("[%d][%d]\n",pos._row, pos._col);
        shortPath.pop();
    }
    cout<<endl;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值