O(n)线性空间的迷宫生成算法
之前所有的迷宫生成算法,空间都是O(mn),时间同样是O(mn),时间上已经不可能更优化,
于是,我就从空间优化上着手,研究一个仅用O(n)空间的生成算法。
我初步的想法是,每次生成一行,生成后立即输出,而其连通性的信息用并查集保存。
然而这时却遇到阻力:不可能简单保存连通性信息就能完成。
因为通过上一行的信息去生成下一行的时候,仅靠连通性信息你无法知道你能不能结束当前路径上的连结,
也就是说你不能判断你能不能生成一个死胡同。
后来想了一下,改进了一下并查集,让它的父结点多保存一个信息:当前行与本结点连通的格子数
看这个例子:
━┳━━┳━━┳━━━━┳━━┳━━┳┓
┣┓┗━┃┃━━┛━━━┓┃┃┃┗┓┃┃┃
┃┗┳━┫┗━━┓┏━━┫┏┛┣━┃┃┃┃
1 1 1 1 2 2 2 2 3 6 6 6 3 3 3 3 3 4 4 5
相同数字的表示它们连通(连向同一个父结点),比如3那个,当前行与本结点连通的格子数=6
也就是3出现的次数。
在生成下一行的时候,每生成一个格子,就得同时更新连通格子数的值,以保证不会生成环路和死路
参考源代码:
#include <iostream>
#include <ctime>
using namespace std;
#define next(n,s) ((n)=(n)%((s)-1)+1)
int fset_size;
struct data
{
int parent;
int level;
int sum;
}*fset;
int fset_pt = 1, fdeep;
int try_alloc(int level)
{
if (fset[fset_pt].level < level)
{
return fset_pt;
}
int lpt = fset_pt;
for (next(fset_pt, fset_size); fset_pt!=lpt; next(fset_pt, fset_size))
{
if (fset[fset_pt].level < level)
{
return fset_pt;
}
}
return 0;
}
int reg_fset(int level)
{
int lpt = fset_pt;
fset[fset_pt].level = level;
fset[fset_pt].parent = 0;
fset[fset_pt].sum = 1;
next(fset_pt, fset_size);
return lpt;
}
int get_parent(int id)
{
int d = id;
for (fdeep=0; fset[id].parent>0; ++fdeep)
id = fset[id].parent;
if (d != id) fset[d].parent = id;
return id;
}
void insert(int a, int b)
{
int pa = get_parent(a), da = fdeep;
int pb = get_parent(b), db = fdeep;
if (pa==pb)
{
}
else if (da<=db)
{
fset[pa].parent = pb;
fset[pb].level = max(fset[pa].level, fset[pb].level);
fset[pb].sum += fset[pa].sum-1;
}
else
{
fset[pb].parent = pa;
fset[pa].level = max(fset[pa].level, fset[pb].level);
fset[pa].sum += fset[pb].sum-1;
}
}
int is_connect(int a, int b)
{
if (a==b || get_parent(a)==get_parent(b))
return 1;
return 0;
}
struct tile
{
int wall;
int id;
};
char cw[][4]={" ","━","┃","┛","━","━","┗","┻","┃","┓","┃","┫","┏","┳","┣","╋"};
int Gen(int w, int h)
{
int x,y,lx,ly,p;
tile* maze = (tile*)malloc(sizeof(tile)*(w+2));
fset = (data*)malloc(sizeof(data)*(w*2));
fset_size = w;
memset(fset, 0, sizeof(data)*(w*2));
for (x=0; x<=w+1; ++x) maze[x].wall = 7, maze[x].id=0;
maze[0].wall = 15; maze[w+1].wall = 15;
for (y=1; y<=h+1; ++y,maze[0].wall = 11,maze[w+1].wall = 14)
{
lx = 0; ly = 1; x = 0;
fset[0].sum = 0;
p = 15;
if (lx) p &= ~8;
if (ly) p &= ~1;
if (maze[x+1].wall&8) p &= ~4;
if (is_connect(maze[x].id, maze[x+1].id)) p &= ~2;
if (y>h) p &= ~8;
printf(cw[p]);
p &= 4;
printf(cw[p]);
for (x=1; x<=w; ++x)
{
int r, _r = 4;
ly = (maze[x].wall&8);
int id, dsum = 0;
if (lx && ly)
{
insert(maze[x-1].id, maze[x].id);
}
else if (lx==0 && ly==0)
{
maze[x].id = try_alloc(y);
if (maze[x].id==0)
{
fset_size += w;
maze[x].id = try_alloc(y);
fset_size -= w;
}
reg_fset(y+1);
}
else if (lx)
{
maze[x].id = maze[x-1].id;
}
id = get_parent(maze[x].id);
if ((maze[x+1].wall&8) && is_connect(maze[x].id, maze[x+1].id)) _r = 2;
if (y==h && x==w)
{
r = 0;
}
else do
{
r = rand() % _r;
if ((r&2)==0 && try_alloc(y)==0) r |= 2;
if (y>h)
{
r = 2;
}
else if (x==w) r &= ~2;
if (y==h) r &= ~1;
dsum = 0;
if ((r & 1) == 0 ) dsum -= 1;
if (r & 2) dsum += 1;
}
while (y<=h && ((r==0 && (lx==0 && ly==0) || fset[id].sum+dsum<=0 )) );
maze[x].wall = 0;
if (ly) maze[x].wall |= 2;
if (lx)
{
maze[x].wall |= 1;
}
lx = (r&2);
if (lx) maze[x].wall |= 4;
if (r&1) maze[x].wall |= 8;
p = 15;
if (maze[x].wall&4) fset[id].sum += 1;
if ((maze[x].wall&8)==0) fset[id].sum -= 1, fset[0].sum += 1;
fset[id].level = y+1;
if (maze[x].wall&4) p &= ~8;
if (maze[x].wall&2) p &= ~1;
if (maze[x+1].wall&8) p &= ~4;
if (maze[x+1].wall&1) p &= ~2;
printf(cw[p]);
p &= 4;
printf(cw[p]);
}
puts("");
if (y<h)
{
for (x=0; x<=w; ++x)
{
if (maze[x].wall&4) printf(cw[0]); else printf(cw[10]);
int id = get_parent(maze[x].id);
maze[x].id = id;
printf(cw[0]);
}
puts("");
}
else if (y==h)
{
for (x=0; x<=w; ++x)
{
if ((maze[x].wall&4) || x==w) printf(cw[0]); else printf(cw[10]);
int id = get_parent(maze[x].id);
maze[x].id = id;
printf(cw[0]);
}
puts("");
}
}
free(maze);
free(fset);
return 0;
}
int main()
{
srand((unsigned)time(NULL));
Gen(15,10);
return 0;
}
O(n)线性空间的迷宫生成算法的更多相关文章
- [迷宫中的算法实践]迷宫生成算法——递归分割算法
Recursive division method Mazes can be created with recursive division, an algorithm which wo ...
- Clojure——学习迷宫生成
背景 初学clojure,想着看一些算法来熟悉clojure语法及相关算法实现. 找到一个各种语言生成迷宫的网站:http://rosettacode.org/wiki/Maze_generation ...
- php生成迷宫和迷宫寻址算法实例
较之前的终于有所改善.生成迷宫的算法和寻址算法其实是一样.只是一个用了遍历一个用了递归.参考了网上的Mike Gold的算法. <?php //zairwolf z@cot8.com heade ...
- 《C++游戏开发》十六 游戏中的寻路算法(二):迷宫&A*算法基础
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/10289253 作者:七十一雾央 新浪微博:http: ...
- roguelike地牢生成算法
文章原地址 上一个地图生成算法,这一次是一个地牢的生成算法,是一个国外的人写的算法,用dart语言写,我把它改成了unity-c#. 原作者博客地址:Rooms and Mazes: A Proced ...
- 一个UUID生成算法的C语言实现 --- WIN32版本 .
一个UUID生成算法的C语言实现——WIN32版本 cheungmine 2007-9-16 根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...
- 分布式全局不重复ID生成算法
分布式全局不重复ID生成算法 算法全局id唯一id 在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...
- Java与算法之(12) - 老鼠再闯迷宫(广度优先算法)
贪吃的小老鼠又回来了,这次有什么新的办法吃到奶酪呢? 规则不变,只能上下左右在格子内移动. 因为上次的深度优先算法让老鼠走了不少冤枉路,这次老鼠带来了帮手探路鼠.探路鼠的使用规则如下: 小老鼠按右.下 ...
- C++ 基于凸包的Delaunay三角网生成算法
Delaunay三角网,写了用半天,调试BUG用了2天……醉了. 基本思路比较简单,但效率并不是很快. 1. 先生成一个凸包: 2. 只考虑凸包上的点,将凸包环切,生成一个三角网,暂时不考虑Delau ...
随机推荐
- XML删除节点
XmlDocument doc = new XmlDocument(); doc.Load("Order.xml"); XmlNode xn = doc.SelectSingleN ...
- oracle11g中SQL优化(SQL TUNING)新特性之Adaptive Cursor Sharing (ACS)
1. ACS简介 Oracle Database 11g提供了Adaptive Cursor Sharing (ACS)功能,以克服以往不该共享的游标被共享的可能性.ACS使用两个新指标:sens ...
- 简话Angular 01 初识Angular 数据绑定
1. Angular有哪些突出优点 1) MVC 基于Html-Javascript 2) 依赖注入 3) 数据双向绑定,响应式页面设计 4) 模块化,自定义指令 2. 简话数据绑定 1) 代码: & ...
- BZOJ一天提交(AC) 51纪念
像我这种蒟蒻...一天交了51道题也要纪念... 真是...但是.不知道还有没有机会了... 这样子就会有很多题解要补了...慢慢来吧... 另.AC数已经超过500了还真是历史性的一步啊...
- json 与字符串相互转换,
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...
- 迁移HTML5移动项目到PhoneGap
MyEclipse开年钜惠 在线购买低至75折!立即开抢>> [MyEclipse最新版下载] 一.创建一个新的PhoneGap应用程序项目 PhoneGap应用程序项目的结构与HTML5 ...
- DevExpress v17.2新版亮点—WPF篇(五)
用户界面套包DevExpress v17.2终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress WPF v17.2 新的Hamburger Menu.Sched ...
- 相同类型的对象不能互相转换:java.lang.ClassCastException: com.anhoo.po.UserPo cannot be cast to com.anhoo.po.UserPo
@PostMapping("/findone") public String getone(UserVo userVo) throws IllegalAccessException ...
- 分析:新建短信,当我们接受人RecipientsEditor中输入+86的时候,系统会自动在+86后加入空格
我们可以认为这是一个很人性的格式化操作,在ComposeMessageActivity中系统在调用initRecipientsEditor()方法对联系人进行初始化的时候调用了 PhoneNumber ...
- OO面向对象 课程总结
测试与正确性论证的效果差差异 测试和正确性论证都是对程序进行可靠性的验证. 测试: IEEE提出了对软件测试的定义:使用人工或者自动的手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求 ...