当我们画一个80*50的迷宫时相当于是画了个80*50的方格子,把格子和格子之间的某些墙拆掉,互相连通的格子我们称之为属于同一个集合,如果两个集合不连通,那就称之为不相交集.
画迷宫的过程就是不断地拆除格子与格子之间的墙,直到第一个格子和最后一个格子属于同一个集合算法终止.
不相交集类.
#ifndef _DISJSETS_H
#define _DISJSETS_H
#include <vector>
using namespace std;
class DisjSets{
public:
explicit DisjSets(int numElems);
int find(int x);
void unionSets(int root1,int root2);
private:
vector<int> s;
};
#endif
类的实现
#include "DisjSets.h"
DisjSets::DisjSets(int numElems):s(numElems){
for(int i=0;i<s.size();i++)
s[i]=-1;
}
//按大小求并,s[i]表示i节点的父节点,如果i已是根节点,则s[i]存储树的大小的相反数
void DisjSets::unionSets(int root1,int root2){
if(s[root2]<s[root1]){ //root2 is bigger
s[root2]+=s[root1]; //size of root2 increase
s[root1]=root2; //make root2 a new root
}
else{
s[root1]+=s[root2];
s[root2]=root1;
}
}
//边find边路径压缩
int DisjSets::find(int x){
if(s[x]<0)
return x;
else
//从X到根的路径上的每一个节点都使它的父节点变成根节点
return s[x]=find(s[x]);
}
画迷宫
#include "DisjSets.h"
#include <ctime>
#include <cassert>
#include <cstdlib>
#include <iostream>
int getAdj(int x,int WIDTH,int SIZE);
int main(int argc,char *argv[]){
int WIDTH=5;
int HEIGHT=5;
if(argc==3){
WIDTH=atoi(argv[1]);
HEIGHT=atoi(argv[2]);
}
int SIZE=WIDTH*HEIGHT;
srand((unsigned)time(NULL));
DisjSets labyrinth(SIZE);
vector<pair<int,int> > grap(SIZE);
for(;;){
if(labyrinth.find(0)==labyrinth.find(SIZE-1))
break;
int m=rand()%SIZE;
int n=getAdj(m,WIDTH,SIZE);
int root1=labyrinth.find(m);
int root2=labyrinth.find(n);
if(root1!=root2){
labyrinth.unionSets(root1,root2);
if(n==m-WIDTH)
grap[n].second=1; //n下面的那堵墙拆掉
else if(n==m+1)
grap[m].first=1; //m右面的那堵墙拆掉
else if(n==m+WIDTH)
grap[m].second=1; //m下面的那堵墙拆掉
else if(n==m-1)
grap[n].first=1; //n右面的那堵墙拆掉
}
}
grap[SIZE-1].first=grap[SIZE-1].second=1; //最后那一格子的右面和下面的墙都要拆掉
for(int i=0;i<HEIGHT;i++){
for(int j=0;j<WIDTH;j++){
if(grap[i*WIDTH+j].first==1 && grap[i*WIDTH+j].second==1)
cout<<"O";
else if(grap[i*WIDTH+j].first==0 && grap[i*WIDTH+j].second==0)
cout<<"C";
else if(grap[i*WIDTH+j].first==1 && grap[i*WIDTH+j].second==0)
cout<<"R";
else if(grap[i*WIDTH+j].first==0 && grap[i*WIDTH+j].second==1)
cout<<"D";
}
cout<<endl;
}
return 0;
}
//迷宫的每个格子中用从0开始的自然数填充.下面函数用于找到x格子的一个随机的相邻格子
int getAdj(int x,int WIDTH,int SIZE){
assert( x>=0 && x<SIZE);
int ret=-1;
while(ret<0 || ret>=SIZE){ //首先保证x格子的邻居没有走出迷宫的范围
int r=rand();
if(x%WIDTH==0){ //x格子在迷宫的最左边
if(r%3==0)
ret=x+1;
else if(r%3==1)
ret=x+WIDTH;
else if(r%3==2)
ret=x-WIDTH;
}
else if((x+1)%WIDTH==0){ //x格子在迷宫的最右边
if(r%3==0)
ret=x-1;
else if(r%3==1)
ret=x+WIDTH;
else if(r%3==2)
ret=x-WIDTH;
}
else{ //其他
if(r%4==0)
ret=x-WIDTH;
else if(r%4==1)
ret=x+1;
else if(r%4==2)
ret=x+WIDTH;
else if(r%4==3)
ret=x-1;
}
}
return ret;
}
运行