迷宫的实现

问题描述:实验心理学中的一个典型的问题,心理学家吧一只老鼠从一个无顶的大盒子的入口处赶进迷宫。迷宫设置很多隔壁,对前进方向形成了许多障碍,心理学家在迷宫的唯一出口处放置了一块奶酪,吸引老鼠仔迷宫中寻找通路以到达出口。

  求解思想:回溯法是一种不断试探且及时纠正错误的搜索方法,下面的求解过程采用回溯法。从入口出发,按某一方向向前探索,若能走通(未走过的),即某处可以到达,则到达一个新点,否则试探下一个方向;若所有的方向均没有通路,则沿原路返回前一点,换下一个方向继续试探,直到所有可能的通路都搜索到,或找到一条通路,或无路可走又返回到入口点。这里可以用一个栈来实现,每走一步,将该位置压入栈中,若该点无路可走,则出栈返回上一位置。

  需要解决的四个问题:

  (1)表示迷宫的数据结构

  设迷宫为m行n列,利用数组maze[m][n]来表示一个迷宫,maze[i][j]=0或1,其中0表示通路,1表示不通,2 表示已走过。迷宫该数组四边都为1,代表迷宫四周都是墙。这样就可以保证每个点都有8个方向可以试探。

  入口为(1,1),出口为(6,8)

  1,1,1,1,1,1,1,1,1,1
      0,0,1,1,1,0,1,1,1,1
      1,1,0,1,0,1,1,1,1,1
      1,0,1,0,0,0,0,0,1,1
      1,0,1,1,1,0,1,1,1,1
      1,1,0,0,1,1,0,0,0,1
      1,0,1,1,0,0,1,1,0,1
      1,1,1,1,1,0,1,1,1,1

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stack>
#include<assert.h>

#define N  10
#include<iostream>
using namespace std;

struct pos  //坐标点
{
	int _row;  //行
	int _col;   //列
};

void GetMaze(int* a, int n)   //从文件中读取数据,存储在数组中
{
	assert(a);
	FILE* fout = fopen("E:\\比特科技编程\\数据结构\\迷宫实现\\maze.txt", "r");
	assert(fout);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n;)
		{
			char ch = fgetc(fout);
			if (ch == '1' || ch == '0')
			{
				a[i * n + j] = ch - '0';
				j++;
			}
			else
			{
				continue;
			}
		}
	}
	fclose(fout);
}

bool CheckisAccess(int *a, int n, const pos& next)  //判断是否可以前进
{
	int row = next._row;
	int col = next._col;
	if (row >= 0 && row < n&&col >= 0 && col < n&&a[next._row*n + next._col] == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool searchpath(int* a, int n, pos entry, stack<pos>& paths)
{
	assert(a);
	paths.push(entry);
	while (!paths.empty())  //如果栈为空,就没找到出口
	{
		pos cur = paths.top();
		a[cur._row*n + cur._col] = 2;
		if (cur._row == n - 1 ||cur._col==n-1)
		{
			return true;
		}
		pos next = cur;
		next._row--;//向上搜索
		if (CheckisAccess(a, n, next))
		{
			cur = next;
			paths.push(cur);
			continue;
		}

		next = cur;
		next._col++;//向右搜索
		if (CheckisAccess(a, n, next))
		{
			cur = next;
			paths.push(cur);
			continue;
		}
		next = cur;
		next._row++;//向下搜索
		if (CheckisAccess(a, n, next))
		{
			cur = next;
			paths.push(cur);
			continue;
		}
		next = cur;
		next._col--;// 向左搜索
		if (CheckisAccess(a, n, next))
		{
			cur = next;
			paths.push(cur);
			continue;
		}
		//	next = cur;
		paths.pop();  //如果没有出路,则出栈,原路返回
	}

	return false;
}
void display(int* a, int n)    //打印迷宫
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cout << a[i*n + j] << " ";
		}
		cout << endl;
	}

}

测试代码如下:

#include"MazeMap.h"
#include<stdio.h> 


void test()
{
	int a[N][N];
	GetMaze((int*)a, N);
	stack<pos> paths;   //定义栈
	pos entry = { 2, 0 }; // 调用入口
	cout << searchpath((int*)a, N, entry, paths) << endl;
	display((int*)a, N);
}
int main()
{
	test();
	system("pause");
	return 0;
}


本文出自 “零点时光” 博客,请务必保留此出处http://10741764.blog.51cto.com/10731764/1771950

作者写点废话哈: 1、先是看到手机上有个小游戏,填字游戏,横竖相连,像个迷宫 2、就用Delphi 做了个由 panel 数组 组成的迷宫,墙都是方块,丑死了。 3、再查查网上有不少迷宫样式,其有的迷宫是单墙的,而且任意两处都是想通的。 4、再做了个四面墙都可打通的迷宫,甚至做了个斜线通道的。 5、觉得三角形迷宫更有挑战性,另外想试试以前学的数据结构指针、链表、树、连通图的知识是不是忘光了, 就做了个三角形迷宫,而且索性做成一个完善的 Delphi 控件,而且有不少属性。。。 6、有几个要解释下:1)迷宫是个连通图,每个正三角形与三个倒三角形相连,每个倒三角形与三个正三角形相连; 2)采用递归,从一个节点开始构造整个连通图;3)查找、遍历连通图时用外部二维数组标识来防止重复; 3)构造迷宫采用的是所谓 随机prim 算法;4)迷宫的宽与三角形边长、列数相互制约,迷宫的高由三角形的高 (正三角形的高通过边长计算的)与行数决定;5)使用指针时最容易丢掉 ^ 这个符号,例如某节点是 Pmm 指针型, 对其属性的引用就不能用 Pmm.Value 而必须用 Pmm^.Value ,机器编译时不会提示错误,但运行时老是出错! 6)绘图通过计算三角形的顶点坐标来构造;7)控件父类是 TGraphicControl ,试了好几种最后它最好, 要覆盖 paint 方法绘图;8)构造类时如 FGridWidth 的内部数据与属性 GridWidth 不要混淆使用, 记住 内部数据赋值,属性引用,属性(Published)是给运行期或者设计面板上别人使用的,内部数据是封装的; 9)发布自定义控件前先准备一个包含 类 一样名称的 ICO 的 DCR 文件,好像只有 Delphi7 里的 Image Editor 可以制作,这个工具包括两个文件 ImageEdit.exe 和 ImageD32.dll 两个文件 7、好像前后陆续花了近两个星期吧,终于基本完善了。该学点其他东西了 -- by chenxz
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值