迷宫实现递归版本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 = ; i < row; ++i)
{
for (int j = ; j < col;)
{
char ch = fgetc(FOut);
if (ch == '' || ch == '')
{
a[i*col + j] = ch - '';
++j;
}
}
}
}

//迷宫打印
void PrintMazeMap(int *a, int row, int col)
{
cout << "MazeMap:(row,col):(" << row <<","<< col <<")."<< endl;
for (int i = ; i < row; ++i)
{
for (int j = ; 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+) % ;
switch (dir)
{
case :
cur.row--;
break;
case :
cur.col++;
break;
case :
cur.row++;
break;
case :
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, );
map[m._cur.row*col + m._cur.col] = ;
paths.push(m);
while ()
{
man top = paths.top();
man cur = top.nextPos(top._dir - );
//man cur = top.nextPos(top._dir + 1); 可替换上行,转换为靠右行。 if (cur._cur.col< || cur._cur.row< || cur._cur.col>=col || cur._cur.row>=row)
{
cout << "越界" << endl;
top._dir++;
//top._dir--; 可替换上行,转换为靠右行
paths.pop();
paths.push(top);
continue;
}
//边界,也就是出入口
if ((cur._cur.col == || cur._cur.row == || cur._cur.col == col- || cur._cur.row == row-)
&&map[cur._cur.row*col + cur._cur.col] == )
{
cout << "这里是出入口" << endl;
if (!(cur._cur == entry))
{ map[cur._cur.row*col + cur._cur.col] = ;
paths.push(cur);
cout << "得到出口" <<cur._cur.row<<" "<<cur._cur.col<< endl;
break;
}
} //遍历:
//下一个位置为当前方向的下一个位置
if (map[cur._cur.row*col + cur._cur.col] != )
{
map[cur._cur.row*col + cur._cur.col] += ; if (map[cur._cur.row*col + cur._cur.col] == )
{
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] = ;
paths.pop();
}
}
map[cur._cur.row*col + cur._cur.col] = ;
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 -
|| entry._cur.col == col -
||entry._cur.row ==
// || entry._cur.col == 0 //注,这一行的注释主要是明确出口的具体位置不是左边。 可以改进为结束判断是:该点是边界,但不是程序传入的迷宫入口。(即是出口)
)
&& map[entry._cur.row*col + entry ._cur.col] !=
)
{
paths.push(entry);
return;
}
else
{
paths.push(entry);
tmp = entry.nextPos(entry._dir-);
    //获得下一个可以通行的位置
while (map[tmp._cur.row*col + tmp._cur.col] == )
{
tmp = entry.nextPos(tmp._dir+);
}
entry = tmp;
GetNextAccessPath(map, row, col, entry);
}
}
void main()
{
int a[][] = {};
::GetMazeMap((int*)a, , );
Step ent = { , };
man entm = { { , }, };
GetMazePaths((int*)a, , , ent); //非递归方式
//GetNextAccessPath((int*)a, 10, 10, man(ent, 0)); //递归方式 ::PrintMazeMap((int*)a, , );
::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++.

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

  1. hdu5044 Tree 树链拆分,点细分,刚,非递归版本

    hdu5044 Tree 树链拆分.点细分.刚,非递归版本 //#pragma warning (disable: 4786) //#pragma comment (linker, "/ST ...

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

    AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树.   2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1).   也就是说,AVL树,本质上 ...

  3. [ C语言 ] 迷宫 迷宫生成器 [ 递归与搜索 ]

    [原创]转载请注明出处 [浙江大学 程序设计专题] [地图求解器] 本题目要求输入一个迷宫地图,输出从起点到终点的路线. 基本思路是从起点(Sx,Sy)每次枚举该格子上下左右四个方向,直到走到终点(T ...

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

    学习和参考 下面是支持区间修改和区间查询的zkw线段树模板,先记下来. #include <algorithm> #include <iterator> #include &l ...

  5. 二分法递归版本(c++)

    利用二分法求解在区间[0,π/2]上的根 #include<iostream> #include <cmath> using namespace std; double dic ...

  6. 移动一根火柴使等式成立js版本(递归)

    修改成递归版本 思路: 1.设定规则数组,比如:1加一根火柴只可以变成7. 2.设定方法数组,比如:一个数增加了一根火柴,其他的数必然减少一根火柴. 3.增加Array方法,由元素名和方法,得到规则对 ...

  7. JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)

    import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; ...

  8. c++链表归并排序的迭代版本

    之前用js写了个归并排序非递归版,而这一次,c++封装链表的时候也遇到了一个归并排序的接口.邓老师实现了递归版本的归并排序,但是递归的调用函数栈的累积是很占内存空间的.于是乎,那试试在链表结构上实现以 ...

  9. 逆转序列的递归/尾递归(+destructuring assignment)实现(JavaScript + ES6)

    这里是用 JavaScript 做的逆转序列(数组/字符串)的递归/尾递归实现.另外还尝鲜用了一下 ES6 的destructuring assignment + spread operator 做了 ...

随机推荐

  1. 【zabbix】自定义监控项key值

    说明: zabbix自带的默认模版里包括了很多监控项,有时候为了满足业务需求,需要根据自己的监控项目自定义监控项,这里介绍一种自定义监控项的方式. 1,首先编写自定义监控脚本,本文以监控httpd进程 ...

  2. macOS Sierra上ssh免密码登录linux服务器

    1.生成私钥文件 在客户端终端下输入以下命令 ssh-keygen -t rsa 每次执行 ssh-keygen -t rsa 产生的私钥文件都会不同 如果文件"~/.ssh/id_rsa& ...

  3. git 更新某个文件

    1.拉取某个仓库的某个文件 git fetch git checkout origin/master test.php

  4. 开发者不可不知的五款DIY快速开发工具,你造吗

    对于非专业的移动开发者,弱化编程能力的快发开发工具实用性够强,无需编程只要借助工具提供的各种功能模块,就能开发出属于自己的应用,而支持DIY更能使应用开发锦上添花,借助快速开发工具开发出属于自己的“能 ...

  5. SVN文件版本太旧问题解决

    错误信息如下: E155036: The working copy at '/Users/...' is too old (format 10) to work with client version ...

  6. playbook管理配置文件

    前言:在生产环境中,经常需要更改多台机器配置文件,所以用playbook来实现nginx配置文件的管理 一.更新nginx配置文件并重新加载 1. 创建对应目录结构 mkdir -p /etc/ans ...

  7. windows使用IPC和文件共享

    远程访问windows资源有很多方式,如果给自己用可以使用ipc或开启共享设置只共享给特定用户.如果给所有人用,可以开启everyone共享和guest账户 { "远程获取Windows资源 ...

  8. shell进阶教程

    背景:就自己常用的shell脚本写作风格,总结了一些知识点.也是作为交接工作的一部分文档.部分内容单独写 #!/bin/sh # shell脚本进阶教程 # 1.常用知识点:变量设置/日期设置/格式化 ...

  9. 20145328 《Java程序设计》第10周学习总结

    20145328 <Java程序设计>第10周学习总结 资料学习内容总结 网络编程 13.1 网络概述 网络编程技术是当前一种主流的编程技术,随着联网趋势的逐步增强以及网络应用程序的大量出 ...

  10. ISSCC 2017论文导读 Session 14 Deep Learning Processors,A 2.9TOPS/W Deep Convolutional Neural Network SOC

    最近ISSCC2017大会刚刚举行,看了关于Deep Learning处理器的Session 14,有一些不错的东西,在这里记录一下. A 2.9TOPS/W Deep Convolutional N ...