简单介绍:

考虑一个迷宫的生成,一个简单算法就是从各处的墙壁开始(除入口和出口之外)。此时,不断地随机选择一面墙,如果被该墙分割的单元彼此不联通,那么就把这面墙拆掉。重复这个过程直到开始单元和终止单元联通,那么就得到一个迷宫。实际上不断的拆掉墙壁直到每个单元都可以从其他单元到达更好(这会使迷宫产生更多误导的路径)。

因此主要是两个问题:

1. 拆掉墙如果两个单元不连通。

2. 保留墙如果两个单元已经联通。

这里用于判断不同单元是否在同一集合的数据结构即为不相交集类。

基本知识:

即我们要建立多个等价类,联通的元素放在同一个等价类里面。

对应的,需要两个操作:

1. 将两个元素放到一个等价类里的话,采用union操作。

2. 查找某个元素在哪个等价类里,采用find操作。根据find的返回值可以判断两个元素是否在一个等价类里。

可以用数组来记录,程序里我使用的是vector(仿照书里的)。

举个例子看可能比较清楚:

假设元素ID刚开始为 0 1 2 3 4 5 6 7 8 9

建立相同大小的数组s,数组初始化值均为-1。

最直观的处理,比如union(4,5)即使s[5] = 4。(约定union(x,y)使得s[y]=x,效果是相同的)。

find(4)会直接返回4本身,因为s[4]<0。

而find(5)则递归调用,实际上为:find(5) = find(s[5]) = 4,因此判断出4,5属于同一个等价类(我觉得可以理解为4这个结点即为等价类的代表)。

find最坏情形运行时间为O(N),因为对N个元素,有可能建立一个深度为N-1的树。

因此对union和find操作都进行了改进。

为了控制树的深度,可以重写union的方式,比如unionBySize,unionByHeight,书上都介绍,这里就不说了。此时find运行时间为O(N)。

另外对于find巧妙的改进是路径压缩,即当find(x)调用时,修改递归找到的结点直接指向等价类的代表结点,使得路径上的结点移近根结点,这样下次调用时就很快了。

正如书上所说:

这种数据结构实现起来很简单,每个例程只需要几行代码,而且可以使用一个简单的数组。

可以看到迷宫差别很大,我只是使得入口出口两个单元连通起来即结束循环。

效率什么的没有考虑。

所有的代码:数据集合类,迷宫生成类

/********************************************************************************
 **
 **       Filename:  DisjSets.h
 **
 **    Description:
 **
 **        Version:  1.0
 **        Created:  2011年12月06日 11时43分46秒
 **       Revision:  none
 **       Compiler:  gcc
 **
 **         Author:  zhy (), izualzhy@163.com
 **        Company:
 **
 *********************************************************************************/
#ifndef DISJSETS_H
#define DISJSETS_H
#include <vector>
#include <iostream>
using namespace std;class DisjSets {public:explicit DisjSets(int numElements);int find(int x);void unionSets(int root1, int root2);private:vector<int> s;
};
#endif//DISJSETS_H

/********************************************************************************
 **
 **       Filename:  DisjSets.cpp
 **
 **    Description:
 **
 **        Version:  1.0
 **        Created:  2011年12月06日 11时45分09秒
 **       Revision:  none
 **       Compiler:  gcc
 **
 **         Author:  zhy (), izualzhy@163.com
 **        Company:
 **
 *********************************************************************************/
#include "DisjSets.h"DisjSets::DisjSets(int numElements) : s(numElements)
{for ( int i=0; i<s.size(); ++i)s[i] = -1;
}int DisjSets::find(int x)
{//cout << "DisjSets::find x= " << x << "\ts[x] = " << s[x] << endl;if (s[x]<0)return x;else {s[x] = find(s[x]);return s[x];}
}void DisjSets::unionSets(int root1, int root2)
{if (s[root1]>s[root2]) {s[root1] = root2;} else {if (s[root1]==s[root2])s[root1]--;s[root2] = root1;}
}

/********************************************************************************
 **
 **       Filename:  MazeDataGenerator.h
 **
 **    Description:  generator the data of maze
 **
 **        Version:  1.0
 **        Created:  2011年12月06日 14时49分09秒
 **       Revision:  none
 **       Compiler:  gcc
 **
 **         Author:  zhy (), izualzhy@163.com
 **        Company:
 **
 *********************************************************************************/
#ifndef MAZEDATAGENERATOR_H
#define MAZEDATAGENERATOR_H
#include <vector>
#include "DisjSets.h"
class Room{public:Room(int row, int col) :i(row) ,j(col){for ( int i=0; i<4; ++i)wall[i] = true;}int i;int j;bool wall[4];bool operator==(const Room &room2){return ((this->i)==(room2.i) && (this->j==room2.j));}
};class MazeDataGenerator {public:enum Direction{NORTH,EAST,SOUTH,WEST};MazeDataGenerator(int row, int column);~MazeDataGenerator(){delete mData;mData = NULL;for ( int i=0; i<mRows; ++i)for ( int j=0; j<mColumns; ++j)delete mRoom[i][j];for ( int i=0; i<mRows; ++i)delete [] mRoom[i];delete [] mRoom;}void print();private:bool isConnected(Room *room1, Room *room2) {return (mData->find(room1->i*mColumns+room1->j)==mData->find(room2->i*mColumns+room2->j));}void initRoad();bool connectTworoom(Room *room1, Room *room2, Direction d);private:DisjSets *mData;Room ***mRoom;int mColumns;int mRows;
};
#endif//MAZEDATAGENERATOR_H

/********************************************************************************
 **
 **       Filename:  MazeDataGenerator.cpp
 **
 **    Description:
 **
 **        Version:  1.0
 **        Created:  2011年12月06日 14时51分42秒
 **       Revision:  none
 **       Compiler:  gcc
 **
 **         Author:  zhy (), izualzhy@163.com
 **        Company:
 **
 *********************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "MazeDataGenerator.h"MazeDataGenerator::MazeDataGenerator(int row, int column) :mRows(row) ,mColumns(column)
{srand(time(NULL));mData = new DisjSets(row*column);mRoom = new Room**[row];for ( int i=0; i<row; ++i)mRoom[i] = new Room*[column];for ( int i=0; i<row; ++i)for ( int j=0; j<column; ++j)mRoom[i][j] = new Room(i,j);mRoom[0][0]->wall[NORTH] = mRoom[0][0]->wall[EAST] = false;mRoom[mRows-1][mColumns-1]->wall[SOUTH] = mRoom[0][0]->wall[WEST] = false;initRoad();
}void MazeDataGenerator::initRoad()
{printf("%s\n",__FUNCTION__);Room *room = mRoom[0][0];while (!isConnected(mRoom[0][0],mRoom[mRows-1][mColumns-1])) {Direction side = (Direction)(rand()%4);int i = room->i;int j = room->j;switch(side) {case NORTH:i = room->i-1;break;case SOUTH:i = room->i+1;break;case EAST:j = room->j-1;break;case WEST:j = room->j+1;break;}if (i<0 || i>=mRows || j<0 || j>=mColumns)continue;if (!isConnected(mRoom[room->i][room->j],mRoom[i][j]))connectTworoom(mRoom[room->i][room->j],mRoom[i][j],side);room = mRoom[i][j];//print();}
}bool MazeDataGenerator::connectTworoom(Room *room1, Room *room2, Direction d)
{//printf("%s\n",__FUNCTION__);//printf("(%d,%d)-->(%d,%d)\n",room1.i,room1.j,room2.i,room2.j);if (room1==room2)return false;int index1 = room1->i*mColumns+room1->j;int index2 = room2->i*mColumns+room2->j;int root1 = mData->find(index1);int root2 = mData->find(index2);if (root1==root2) return false;mData->unionSets(root1,root2);room1->wall[d] = false;room2->wall[(d+2)%4] = false;return true;
}void MazeDataGenerator::print()
{printf("%s\n",__FUNCTION__);for ( int i=0; i<mRows; ++i) {for ( int j=0; j<mColumns; ++j)printf("%2d ",mData->find(mRows*i+j));printf("\n");}for (int j=0; j<mColumns; ++j)printf("__");printf("\n");for ( int i=0; i<mRows; ++i) {for ( int j=0; j<mColumns; ++j) {char s[3] = "  ";if (((j-1<0) && i!=0) || mRoom[i][j]->wall[1]) s[0]='|';if ((i+1)>=mRows || mRoom[i][j]->wall[2]) s[1]='_';printf("%s",s);if ((j+1)==mColumns && i!=mRows-1) printf("|");}printf("\n");}
}

参考资料:

数据结构与算法分析—C++描述

转载自 http://www.cppblog.com/izualzhy/archive/2011/12/11/161913.html

不相交集类以及应用迷宫生成相关推荐

  1. 不相交集类及其应用生成迷宫

    // 任意合并两个不相交集合void unionSets( int root1, int root2 ){s[ root2 ] = root1;} // 寻找 x 所在集合int find( int ...

  2. c语言 迷宫深度遍历 算法,图的遍历迷宫生成算法浅析

    1. 引言 在平常的游戏中,我们常常会碰到随机生成的地图.这里我们就来看看一个简单的随机迷宫是如何生成. 2. 迷宫描述随机生成一个m * n的迷宫,可用一个矩阵maze[m][n]来表示,如图:   ...

  3. python实现地牢迷宫生成

    python实现地牢迷宫生成 基本属性 生成房间 生成墙壁 生成门口 生成通道 基本属性 定义当前地牢的等级,地图长宽,房间数量,房间的最小最大长度,如下 class Map:def __init__ ...

  4. java动画迷宫寻路_[人工智能] 迷宫生成、寻路及可视化动画

    前言 数据结构准备 迷宫生成算法 迷宫寻路算法 前言 本次带来迷宫相关的算法,迷宫的算法涉及到不少经典的图论算法,在游戏中NPC这些算法被大量的运用,深入了解和学习这些算法是为开发游戏打下坚实的基础. ...

  5. Unity大型场景程序化生成及优化技术—FPS迷宫生成和优化

    Unity大型场景程序化生成及优化技术-FPS迷宫生成和优化 1.知名游戏中的大型场景生成 场景程序化生成技术是一个广泛应用在游戏开发中的技术,较早的使用这类技术有名游戏<暗黑破坏神>系列 ...

  6. 数据结构之不相交集类

    不相交集类是解决等价关系问题的一种非常有效的手段!等价关系是一种关系R,他满足自反性,对称性与传递性.有人说散列是最艺术的数据结构,优先队列是最优雅的数据结构 而不相交集类就是最简洁的数据结构!这些说 ...

  7. 迷宫生成算法和迷宫寻路算法

    迷宫生成算法和迷宫寻路算法 大学二年级的时候,作为对栈这个数据结构的复习,我制作了一个迷宫生成算法的小程序,当时反响十分好,过了几天我又用自己已经学的DirectX技术制作了DirectX版的程序.这 ...

  8. js迷宫生成与迷宫求解算法

    迷宫问题是一个很经典的问题,本文记叙迷宫的生成和求解(深度优先),完整dome见文章末尾(包括动画演示) 所涉及迷宫为: 方形规则迷宫 只有一个出口和一个入口 路径连续 只有一个解 先看效果: a.迷 ...

  9. C#三大迷宫生成算法

    今天介绍一下很经典的三大迷宫算法的C#实现,即随机普利姆算法,深度优先算法和十字分割(也就是递归分割算法).实现参考了[ActionScript 3] 三大迷宫生成算法一文(生成的迷宫预览图也使用的该 ...

最新文章

  1. 宝可梦维护服务器,宝可梦大师卡在登录界面进不去,宝可梦大师为啥玩不了
  2. docker安装运行rancher脚本
  3. 使用memcached显著提升站点性能
  4. 算法笔记_二分查找/斐波那契查找
  5. html css js php常用网页代码汇总合集(一)网页设计入门代码知识汇总1
  6. 【精讲】软件工程用图的各个阶段及其应用(详细)系统流程图、数据流图、数据字典、ER图、状态转换图、层次方框图、Warnier图、IPO图、层次图、HIPO图、结构图、程序流程图、盒图等
  7. 软件可靠性方法 学习笔记
  8. 伪春菜.ayc(.dic)文件解密
  9. 服务器监控系统图解,[图解]Attribute实现服务器监控5大步骤
  10. SpringBoot之使用Security
  11. 关于使用U盘制作简单windows开机加密狗
  12. Python实现计算MD5
  13. oracle数据表空间与数据文件,oracle的表空间及数据文件
  14. 和差角证明托勒密定理
  15. 使用ssr退出后,电脑能连上无线网,但是不能上网的解决方法
  16. 数据中心网络设备管理(二)
  17. day13_下 Class中三大护法 及常用属性 单例模式(扩展)
  18. Python基础教程让小白从入门到精通(一)爬虫分析
  19. 一月笔记-JAVA-超市管理系统
  20. CLion 拼写错误 如何关闭拼写错误

热门文章

  1. git服务器搭建问题
  2. PortableApps的使用方法
  3. CSAPP(4):存储器层次结构
  4. 非常认同的《SEO优化大全》
  5. WEB程序代码优化入手的几方面
  6. Visual Web Development 2005开发ASP.NET使用小技巧
  7. MD5 - Bump Mapping
  8. C++排序算法实现(更新中)
  9. 《OpenCV3编程入门》学习笔记4 OpenCV数据结构与基本绘图
  10. 列名无效怎么解决_PowerQuery批量合并Excel,前面有空行且不相等的解决办法