之前所有的迷宫生成算法,空间都是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)线性空间的迷宫生成算法的更多相关文章

  1. [迷宫中的算法实践]迷宫生成算法——递归分割算法

    Recursive division method        Mazes can be created with recursive division, an algorithm which wo ...

  2. Clojure——学习迷宫生成

    背景 初学clojure,想着看一些算法来熟悉clojure语法及相关算法实现. 找到一个各种语言生成迷宫的网站:http://rosettacode.org/wiki/Maze_generation ...

  3. php生成迷宫和迷宫寻址算法实例

    较之前的终于有所改善.生成迷宫的算法和寻址算法其实是一样.只是一个用了遍历一个用了递归.参考了网上的Mike Gold的算法. <?php //zairwolf z@cot8.com heade ...

  4. 《C++游戏开发》十六 游戏中的寻路算法(二):迷宫&A*算法基础

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/10289253 作者:七十一雾央 新浪微博:http: ...

  5. roguelike地牢生成算法

    文章原地址 上一个地图生成算法,这一次是一个地牢的生成算法,是一个国外的人写的算法,用dart语言写,我把它改成了unity-c#. 原作者博客地址:Rooms and Mazes: A Proced ...

  6. 一个UUID生成算法的C语言实现 --- WIN32版本 .

    一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...

  7. 分布式全局不重复ID生成算法

    分布式全局不重复ID生成算法 算法全局id唯一id  在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...

  8. Java与算法之(12) - 老鼠再闯迷宫(广度优先算法)

    贪吃的小老鼠又回来了,这次有什么新的办法吃到奶酪呢? 规则不变,只能上下左右在格子内移动. 因为上次的深度优先算法让老鼠走了不少冤枉路,这次老鼠带来了帮手探路鼠.探路鼠的使用规则如下: 小老鼠按右.下 ...

  9. C++ 基于凸包的Delaunay三角网生成算法

    Delaunay三角网,写了用半天,调试BUG用了2天……醉了. 基本思路比较简单,但效率并不是很快. 1. 先生成一个凸包: 2. 只考虑凸包上的点,将凸包环切,生成一个三角网,暂时不考虑Delau ...

随机推荐

  1. iddea代码调试debug篇

    代码调试debug篇 主要看图,看图一目了然.  断点的设定和eclipse一样,只要点一下就可以,下面是我设定的几个断点,再下面的三个窗口是用来调试代码的,这个和eclipse类似 调试常用的快捷键 ...

  2. laravel更新时区:

    config/app.php 'timezon'='UTC'  或 'timezone'='Asia/Shanghai'

  3. SQL*Loader 详解

    在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法: 1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中2. 建立数据库间的 ...

  4. Linux内核分析-使用gdb跟踪调试内核从start_kernel到init进程启动

    姓名:江军 ID:fuchen1994 实验日期:2016.3.13 实验指导 使用实验楼的虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/a ...

  5. gitignore中常见需要被无视的文件

    gitignore中常见的需要被忽略的文件:例如各个系统.一些软件会自动生成的文件,主要适用于web项目. 复制后,保存进.gitignore文件中即可. # Project node_modules ...

  6. L1-035 情人节

    以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家.第2个赞和第14个赞的,我介绍你俩认识…………咱三吃饭…你俩请…”.现给出此贴下点赞的朋友名单,请你找出那两位要请客的倒霉蛋. 输入格式: ...

  7. iOS工程中如何去掉第三方的警告

    一)第一种方法 在工程中有警告的地方,右键选择Review in log,然后就能看到类似[Wnonnull]这样的警告, 然后在工程buildSettings中的Other Warning Flag ...

  8. 【重大更新】DevExpress v17.2新版亮点—WPF篇(三)

    DevExpress年终击穿底价,单套授权低至67折!仅剩最后10天!查看详情>>> 用户界面套包DevExpress v17.2终于正式发布,本站将以连载的形式为大家介绍各版本新增 ...

  9. Tesseract-OCR 训练教程(二) 合并新的训练文件

    在原有训练数据的基础上,如果有新的字符训练信息需要加入,所有数据重新校准一遍就累死人了.... 经研究找到实用合并方法(红色部分为示例,实际应为你自己生成的文件名): 在新的训练数据生成.box 和. ...

  10. 一款经典的 jQuery Lightbox 灯箱效果

    一个灯箱效果的图片展示插件. 版本: jQuery v1.2.3+ jQuery Lightbox v2.7.1 github 实例预览 使用方法 载入 CSS 文件 <link rel=&qu ...