迷宫实现递归版本C++

迷宫实现递归版本C++

问题描述:

////////////////////////////////////////////////////////////
//题目:迷宫求解问题。

大致思路:

//1、入口,出口判断/程序终止判定:4个方位的坐标边界比较,表明到了出入口。
//2-1、求解原理1:暴力处理,从入口点开始,对其四个方向进行可行性判别,获取下一位置,重复,知道走到出口。
//2-2、求解原理2:对于有出口的迷宫,如果你一直靠右,或者靠左行走,必然能够走到出口。这个方案省去了1中暴力队每个方向的判别。
//3、走过的路线,具体坐标的值修改为2,然后将走过的点坐标入栈保存。
//4、优化点①:可能存在死胡同或者环形路线,那么必然会绕远路。所以对3、中的修改值为2改进为+=2,可以具体得出经过某位置几次
//5、优化点②:根据3、 4、可以判断出走过的没必要的路线,记录值为4的点,然后对栈进行出栈操作,可以做到优化部分路线。
//6、待完善点:没有给出迷宫最短路线的解答。
////////////////////////////////////////////////////////////

//工程目录下 MazeMap.txt中的地图表示

//1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
//0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1
//1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
//1 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 0 0 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 0 0 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 0 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 0 0 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1
//1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1
//1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
//1 1 0 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1
//1 1 0 1 0 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
//1 1 0 1 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1
//1 1 0 1 0 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1
//1 1 0 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1
//1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

代码示例:

//由文件读取迷宫地图。void GetMazeMap(int *a,int row,int col)
{
    FILE *FOut;
    fopen_s(&FOut,"MazeMap.txt", "r");

    assert(FOut);

    for (int i = 0; i < row; ++i)
    {
        for (int j = 0; j < col;)
        {
            char ch = fgetc(FOut);
            if (ch == ‘0‘ || ch == ‘1‘)
            {
                a[i*col + j] = ch - ‘0‘;
                ++j;
            }
        }
    }
}
//迷宫打印
void PrintMazeMap(int *a, int row, int col)
{
    cout << "MazeMap:(row,col):(" << row <<","<< col <<")."<< endl;
    for (int i = 0; i < row; ++i)
    {
        for (int j = 0; j < col; ++j)
        {
            cout << a[i*col + j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

//位置坐标类。
struct Step
{
    int row;// 行
    int col;//列
    bool operator==(Step &s)
    {
        return row == s.row&&col == s.col;
    }
};

//在程序中对迷宫进行遍历时除了坐标,更给出具体方向的类man
struct man
{
    man(Step s, int d)
    :_cur(s)
    , _dir(d)
    {}
    Step _cur;
    int _dir;// 0-3 表明4个方向

    man nextPos(int dir)
    {
        Step cur = _cur;
        dir = (dir+4) % 4;
        switch (dir)
        {
        case 0:
            cur.row--;
            break;
        case 1:
            cur.col++;
            break;
        case 2:
            cur.row++;
            break;
        case 3:
            cur.col--;
            break;
        }
        return man(cur, dir);
    }
};

stack<man> paths;
//打印具体走过的迷宫路线的坐标(含方向)
void PrintPathStep()
{
    while (!paths.empty())
    {
        man tmp = paths.top();
        cout << "[" << tmp._cur.row << "," << tmp._cur.col << "]:" << tmp._dir << "" << "-->";

        paths.pop();
    }
    cout << "Over!" << endl;
}

//给定map和入口点坐标,求迷宫解
void GetMazePaths(int *map, int row, int col, Step& entry)
{
    //当前位置.
    man m(entry, 0);
    map[m._cur.row*col + m._cur.col] = 2;
    paths.push(m);
    while (1)
    {
        man top = paths.top();
        man cur = top.nextPos(top._dir - 1);
        //man cur = top.nextPos(top._dir + 1);   可替换上行,转换为靠右行。

        if (cur._cur.col<0 || cur._cur.row<0 || cur._cur.col>=col || cur._cur.row>=row)
        {
            cout << "越界" << endl;
            top._dir++;
            //top._dir--;   可替换上行,转换为靠右行
            paths.pop();
            paths.push(top);
            continue;
        }
        //边界,也就是出入口
        if ((cur._cur.col == 0 || cur._cur.row == 0 || cur._cur.col == col-1 || cur._cur.row == row-1)
            &&map[cur._cur.row*col + cur._cur.col] == 0)
        {
            cout << "这里是出入口" << endl;
            if (!(cur._cur == entry))
            {

                map[cur._cur.row*col + cur._cur.col] = 2;
                paths.push(cur);
                cout << "得到出口" <<cur._cur.row<<" "<<cur._cur.col<< endl;
                break;
            }
        }

        //遍历:
        //下一个位置为当前方向的下一个位置
        if (map[cur._cur.row*col + cur._cur.col] != 1)
        {
            map[cur._cur.row*col + cur._cur.col] += 2;

            if (map[cur._cur.row*col + cur._cur.col] == 4)
            {
                Step tmp;
                tmp.row = cur._cur.row;
                tmp.col = cur._cur.col;
                //////////////////////////////////////////////////////////////////////////////
                //回退过程。
                while (paths.top()._cur.row != tmp.row || paths.top()._cur.col != tmp.col)
                {
                    map[paths.top()._cur.row*col + paths.top()._cur.col] = 1;
                    paths.pop();
                }
            }
            map[cur._cur.row*col + cur._cur.col] = 2;
            paths.push(cur);
        }
        else
        {
            top._dir++;
            //top._dir--;     可替换上行,转变为靠右行方案
            paths.pop();
            paths.push(top);
        }
    }
}

//递归方式求解迷宫路线问题。思路为靠左行方案//注:递归方式没有如非递归方式的死胡同排除等优化,只是单纯的靠左行得到路线。
void GetNextAccessPath(int *map, int row, int col, man& entry)
{
    man tmp(entry);
    if (
        (
        entry._cur.row == row - 1
        || entry._cur.col == col - 1
        ||entry._cur.row == 0
    //    || entry._cur.col == 0     //注,这一行的注释主要是明确出口的具体位置不是左边。   可以改进为结束判断是:该点是边界,但不是程序传入的迷宫入口。(即是出口)    )
        &&    map[entry._cur.row*col + entry    ._cur.col] != 1
        )
    {
        paths.push(entry);
        return;
    }
    else
    {
        paths.push(entry);
        tmp = entry.nextPos(entry._dir-1);    //获得下一个可以通行的位置
        while (map[tmp._cur.row*col + tmp._cur.col] == 1)
        {
            tmp = entry.nextPos(tmp._dir+1);
        }
        entry = tmp;
        GetNextAccessPath(map, row, col, entry);
    }
}
void main()
{
    int a[20][20] = {};
    ::GetMazeMap((int*)a, 20, 20);
    Step ent = { 2, 0 };
    man entm = { { 2, 0 }, 1 };
    GetMazePaths((int*)a, 20, 20, ent);   //非递归方式
    //GetNextAccessPath((int*)a, 10, 10, man(ent, 0));   //递归方式

    ::PrintMazeMap((int*)a, 20, 20);
    ::PrintPathStep();
    system("pause");
}

运行结果实例:

得到出口19 2
MazeMap:(row,col):(20,20).
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1
1 1 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 0 0 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 0 0 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 0 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 0 0 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 2 1 1
1 1 0 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 1 1
1 1 0 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 2 2 2 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 2 1 2 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 2 1 2 2 2 1 0 0 0 1 1 1 1 1 1 1 1 1
1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

[19,2]:2--> [18,2]:3--> [17,2]:3--> [16,2]:3--> [15,2]:3--> [14,2]:3--> [14,3]:4--> [14,4]:0--> [15,4]:1--> [16,4]:1--> [17,4]:1--> [18,4]:5--> [18,5]:4--> [18,6]:4--> [17,6]:3-->
[16,6]:3--> [15,6]:3--> [14,6]:3--> [13,6]:3--> [12,6]:3--> [12,7]:4--> [12,8]:4--> [12,9]:4--> [12,10]:4--> [12,11]:4--> [12,12]:0--> [12,12]:3--> [12,13]:4--> [12,14]:4--> [12,15]:4-->
[12,16]:4--> [12,17]:4--> [11,17]:3--> [10,17]:3--> [9,17]:3--> [8,17]:3--> [7,17]:3--> [6,17]:3--> [5,17]:3--> [4,17]:3--> [3,17]:3--> [2,17]:3--> [2,16]:2--> [2,15]:2--> [2,14]:2-->
[2,13]:2--> [2,12]:2--> [2,11]:2--> [2,10]:2--> [2,9]:2--> [2,8]:2--> [2,7]:2--> [2,6]:2--> [2,5]:2--> [2,4]:2--> [2,3]:2--> [2,2]:2--> [2,1]:2--> [2,0]:2--> Over!

注:程序中的地图大小可由文件中定义给出。

然后数组表示可以改进为动态分配。

具体关于二维数组做参数或如何动态申请二维数组的方案可参考:Effective-C++.

时间: 2024-12-29 04:40:36

迷宫实现递归版本C++的相关文章

数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1). 也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树). 对Avl树进行相关的操作最重要的是要保持Avl树的平衡条件.即对Avl树进行相关的操作后,要进行相应的旋转操作来恢复Avl树的平衡条件. 对Avl树的插入和删除都可以用递归实现,文中也给出了插入的非递归版本,关键在于要用到栈. 代码如下: #inclu

hdu 4850 Wow! Such String! 构造 或 欧拉路径并改写成非递归版本

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4850 跟这道题也算是苦大仇深了... 题意:构造一个由26个小写字母组成的.无长度为4的重复子串的字符串(要求出能构造出的最大长度) 符合要求的长度为4的字符串有4^26个 容易猜最大长度是:4^26+3 = 456979 比赛的时候想法是要让各个字母出现得尽量“均匀” 用了一个cnt数组记录26个字母出现的次数 每次都选择出现次数最小的.不与前面重复的字母加上去 然而稍微写得有点歪,最后构造出了长

0-1背包打印路径(递归和非递归版本)

简单的0-1背包打印路径问题,我们可以记录一个p[][]数组来判断,当前物品是否被选中,最后按照记录输出,注意是逆序. #include<stdio.h> #include<string.h> int main() { int a[25],p[25][10005],i,j,n,m,s[10005]; while(scanf("%d%d",&m,&n)!=EOF){ for(i=1;i<=n;i++) scanf("%d"

快速排序 归并排序的非递归版本 备忘

首先,归并排序,分治,递归解决小的范围,再合并两个有序的小范围数组,便得到整个有序的数组. 这是很适合用递归来写的,至于非递归,便是从小到大,各个击破,从而使得整个数组有序.代码如下: void merge(vector<int> &A, int left, int mid, int right) { int i=left,j=mid+1; vector<int> tmp(right-left+1,0); int k=0; while(i<=mid&&

fibo数求法(递归版本) -- 作者小泽

fibonacci数的递归求法: 1 2 struct Fib 3 { 4 int x1; 5 int x2; 6 }; 7 8 Fib fib(int x) 9 { 10 Fib ans; 11 if(x == 2) 12 { 13 ans.x1 = 0; 14 ans.x2 = 1%MOD; 15 return ans; 16 } 17 Fib temp; 18 int x1 = x/2, x2 = x1 - 1; 19 if(x1%2) 20 { 21 temp = fib(x2); 22

【二分查找】无重复数组的二分查找(非递归版本)

// 二分查找法 #include <iostream> #include <vector> using namespace std; int BinarySearch(vector<int> vec,int target) { // 特殊输入 if(vec.size() <= 0) return -1; // 二分查找(非递归) int low = 0; int mid = 0; int high = vec.size()-1; // 注意:取等号 while(

《算法导论》习题2.3-4 插入排序的递归版本

伪代码: RECURSIVE-INSERT-SORT (A, n) if n>1 RECURSIVE-INSERT-SORT (A ,n-1) InsertLastNumber (A,n) InsertLastNumber (A,n) temp = A[n] i=n-1 while i>0 && A[i]>temp A[i+1] = A[i] i -=1 A[i+1]=temp Java实现: public class RecursiveInsertSort { publ

ZKW线段树 非递归版本的线段树

学习和参考 下面是支持区间修改和区间查询的zkw线段树模板,先记下来. #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <iomanip> #include <cstdlib> #include <cstdio> #include <string> #include <vect

递归解迷宫的问题

突然兴起递归解决了走迷宫问题,对递归的本质加深了印象,一开始用到了STL的set容器,stl容器是排序容器,如果装载自定义对象的时候需要自定义排序函数,最后选择了用向量vector存储路径,vector有队列的性质. 解迷宫的递归流程是,检测四个方向是否可走,遇到死路则原路递归返回false,遇到出口则返回true,并将来的路线保存进队列. #include <Windows.h> #include <stdio.h> #include <stdlib.h> #incl