用不相交集合生成一个迷宫

来源:互联网 发布:拿破仑为什么称帝知乎 编辑:程序博客网 时间:2024/05/16 00:24

  最近看到不相交集,使用不相交集写了一个生成迷宫算法,其实想法很简单,就来分享一下,首先我们对迷宫中的每个格子进行编号,从0到n,先画一个n*m的格子版,然后删除一些边打通各个格子,使之变成连通,我们把边分成横边和纵边,我们可以通过计算,标记打通一条边会使两个格子变成连通,然后用不想交集合进行标记。最后使得所有边都连通起来即可:

  具体操作:先把所有的边编号,放入一个数组内,然后用随机数打乱整个数组,接着对这个数组进行遍历,检测一条边连接的两个小方格,若其不连通,即不在一同一个不想交集合内,则打通他们,否则则不做任何动作,知道所有格子都被遍历完成,得到的边的数组就是生成迷宫了

不相交集源代码:

/** * Created by v on 16-12-13. */public class DisjSets {    private int[] s;    public DisjSets(int numElements){        s=new int[numElements];        for(int i=0;i<s.length;i++){            s[i]=-1;        }    }    public void union(int root1,int root2){        if(s[root1]<s[root2]){            s[root2]=root1;        }else{            if(s[root1]==s[root2]){                s[root2]--;            }            s[root1]=root2;        }    }    public int find(int x){        if(s[x]<0){            return x;        }else {            return s[x]=find(s[x]);        }    }}

  迷宫后台算法:

import java.util.Random;/** * Created by v on 16-12-13. */public class Labyrinth {    private boolean[][][] sides;    private DisjSets disjSets;    /**     *     * 对于一个n*m的迷宫,纵向边共(1+n)*(1+m)条,横向边也一样,     * 因此我们用数组的最后一位表示纵横,z=0为横,z=1为纵     *     * @param rows 迷宫格子的行数     * @param lines 迷宫格子的列数     */    public Labyrinth(int lines, int rows){        sides =new boolean[lines+1][rows+1][2];        disjSets=new DisjSets(rows*lines);        //去除边框处露出来的边        for(int i=0;i<=rows;i++){            sides[lines][i][0]=true;        }        for(int i=0;i<=lines;i++){            sides[i][rows][1]=true;        }        build(lines,rows);        //打通入口与出口        sides[0][0][1]=true;        sides[lines][rows-1][1]=true;    }    //产生一个迷宫    private void build(int lines,int rows){        int[] randomNumbers=new int[rows*lines*2];        //先生成一个包含所有边的编号的数组        for(int i=0;i<randomNumbers.length;i++){            randomNumbers[i]=i;        }        Random random=new Random();        //对整个数组进行打乱处理        for(int i=0;i<randomNumbers.length;i++){            swap(randomNumbers,i,random.nextInt(randomNumbers.length));        }        //对迷宫的每一条边进行处理,若边的两头未连通,则删除边        for(int i=0;i<randomNumbers.length;i++){            int x=randomNumbers[i]%lines;            int z=randomNumbers[i]/rows/lines;            int y=(randomNumbers[i]-z*rows*lines)/lines;            //对于位于边界的边,我们不处理            if(y==0&&z==0){continue;}            if(x==0&&z==1){continue;}            //尝试打通这一条边            if(z==0){                int root1=disjSets.find(x+lines*y);                int root2=disjSets.find(x+lines*(y-1));                if(root1!=root2){                    disjSets.union(root1,root2);                    sides[x][y][z]=true;                }            }else {                int root1=disjSets.find(x+lines*y);                int root2=disjSets.find(x-1+lines*y);                if(root1!=root2){                    disjSets.union(root1,root2);                    sides[x][y][z]=true;                }            }        }    }    //交换两个值    private final void swap(int[] array,int index1,int index2){        int temp=array[index1];        array[index1]=array[index2];        array[index2]=temp;    }    //返回迷宫的某一个边是否被打通,若被打通则返回true    public boolean getSide(int x,int y,int z){        return sides[x][y][z];    }    public int getLines(){        return sides.length;    }    public int getRows(){        return sides[0].length;    }}

  迷宫显示的ui:

import javax.swing.*;import java.awt.*;/** * Created by v on 16-12-13. */public class LabyrinthUI extends JApplet {    LabyrinthPanel panel;    public LabyrinthUI(){        panel=new LabyrinthPanel(40,30);        add(panel);    }    @Override    public void init() {        super.init();        setSize(600,400);    }    private class LabyrinthPanel extends JPanel{        private Labyrinth labyrinth;        public LabyrinthPanel(int lines,int rows){            labyrinth=new Labyrinth(lines,rows);            repaint();        }        @Override        protected void paintComponent(Graphics g) {            super.paintComponent(g);            for(int i=0;i<labyrinth.getLines();i++){                for(int j=0;j<labyrinth.getRows();j++){                    if(!labyrinth.getSide(i,j,0)){                        g.drawLine(50+i*10,50+j*10,                                50+i*10+10,50+j*10);                    }                    if(!labyrinth.getSide(i,j,1)){                        g.drawLine(50+i*10,50+j*10,                                50+i*10,50+j*10+10);                    }                }            }        }    }}
0 0
原创粉丝点击