利用不相交集画迷宫
当我们画一个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; }
运行
本文来自博客园,作者:高性能golang,转载请注明原文链接:https://www.cnblogs.com/zhangchaoyang/articles/1999458.html