現在介紹第二種演算法,使用並查集 合并產生。
簡單介紹一下演算法思想:首先把地圖關鍵點的連結(牆),編號1-x*y*2,然後random shuffle
然後按照打亂後的次序,打通一些牆,用並查集檢查是否要打通的兩邊是已經連通的就行了,
產生的例子如下:
█████████████████████
█ █ █
█████████ █ █ █ █████
█ █ █ █ █ █ █
█ █ █ ███ █████ █ █ █
█ █ █ █ █ █ █ █
█ █ ███ ███ ███ ███ █
█ █ █ █
█████ ███ █ █ ███ ███
█ █ █ █ █ █
█████ ███ ███████ █ █
█ █ █ █
█ ███ █ ███ █ █ █████
█ █ █ █ █ █ █
███ ███████ █ █ ███ █
█ █ █ █ █
█████████████████████
這種演算法產生的特點是,分支數非常的多,較多短小分支,難度往往較DFS產生的簡單
但效率非常高,產生1000*1000的迷宮,只要1秒(DFS產生的常數上要大一些)
但需要一個輔助的並查集資料結構,空間消耗大。
代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SWAP(a,b,c) {c t=a;a=b;b=t;}
int uf[9000000], Map[3000][3000]; //並查集表,迷宮地圖
struct PT{int x; int y;}que[5000000]; //產生序列
int x=10,y=8,xy=0; //x,y指定要產生的大小
int findP(int& n)
{
int a=++n;
while (uf[a]) a=uf[a];
if (a!=n) uf[n] = a;
return n=a;
}
int Ins(PT xy)
{
int a=(xy.y-1)/2*x+(xy.x-1)/2, b=(xy.y&1)?a+1:a+x;
if (findP(a)!=findP(b)) {uf[b] = a; return 1;}
return 0;
}
int main()
{
int n=0,_y,_x,o;
srand(time(NULL)); Map[1][0]=Map[y*2-1][x*2]=1;
for (_y=1; o=_y!=y,_y<=y; ++_y)
for (_x=1; _x<=x; ++_x)
{
if (_x<x)que[n].y = _y*2-1, que[n].x = _x*2,++n;
if (o)que[n].y = _y*2, que[n].x = _x*2-1,++n;
}
for (xy=n,n=0; n<xy; ++n) {int z=rand()%xy; SWAP(que[n],que[z],PT);}
for (n=0; n<xy; ++n)
{
if (!Ins(que[n])) continue;
Map[que[n].y][que[n].x] = 1;
if (que[n].y&1) Map[que[n].y][que[n].x-1] = Map[que[n].y][que[n].x+1] = 1;
else Map[que[n].y-1][que[n].x] = Map[que[n].y+1][que[n].x] = 1;
}
for (_y=0; _y<=y*2; ++_y)
{
for (_x=0; _x<=x*2; ++_x)
if (Map[_y][_x]) fputs(" ", stdout); else fputs("█", stdout);
putchar(10);
}
return 0;
}