Algorithm for equiprobable random square binary matrices with two non-adjacent non-zeros in each row and column

后端 未结 5 1269
遇见更好的自我
遇见更好的自我 2020-12-09 10:22

It would be great if someone could point me towards an algorithm that would allow me to :

  1. create a random square matrix, with entries 0 and 1, such that
  2. <
5条回答
  •  粉色の甜心
    2020-12-09 10:51

    This solution use recursion in order to set the cell of the matrix one by one. If the random walk finish with an impossible solution then we rollback one step in the tree and we continue the random walk.

    The algorithm is efficient and i think that the generated data are highly equiprobable.

    package rndsqmatrix;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.stream.IntStream;
    
    public class RndSqMatrix {
    
        /**
         * Generate a random matrix
         * @param size the size of the matrix
         * @return the matrix encoded in 1d array i=(x+y*size)
         */
        public static int[] generate(final int size) {
            return generate(size, new int[size * size], new int[size],
                    new int[size]);
        }
    
        /**
         * Build a matrix recursivly with a random walk 
         * @param size the size of the matrix
         * @param matrix the matrix encoded in 1d array i=(x+y*size)
         * @param rowSum
         * @param colSum
         * @return 
         */
        private static int[] generate(final int size, final int[] matrix,
                final int[] rowSum, final int[] colSum) {
    
            // generate list of valid positions
            final List positions = new ArrayList();
            for (int y = 0; y < size; y++) {
                if (rowSum[y] < 2) {
                    for (int x = 0; x < size; x++) {
                        if (colSum[x] < 2) {
                            final int p = x + y * size;
                            if (matrix[p] == 0
                                    && (x == 0 || matrix[p - 1] == 0)
                                    && (x == size - 1 || matrix[p + 1] == 0)
                                    && (y == 0 || matrix[p - size] == 0)
                                    && (y == size - 1 || matrix[p + size] == 0)) {
                                positions.add(p);
                            }
                        }
                    }
                }
            }
    
            // no valid positions ?
            if (positions.isEmpty()) {
    
                // if the matrix is incomplete => return null
                for (int i = 0; i < size; i++) {
                    if (rowSum[i] != 2 || colSum[i] != 2) {
                        return null;
                    }
                }
    
                // the matrix is complete => return it
                return matrix;
            }
    
            // random walk 
            Collections.shuffle(positions);
            for (int p : positions) {
                // set '1' and continue recursivly the exploration
                matrix[p] = 1;
                rowSum[p / size]++;
                colSum[p % size]++;
                final int[] solMatrix = generate(size, matrix, rowSum, colSum);
                if (solMatrix != null) {
                    return solMatrix;
                }
    
                // rollback 
                matrix[p] = 0;
                rowSum[p / size]--;
                colSum[p % size]--;
            }
    
            // we can't find a valid matrix from here => return null
            return null;
        }
    
        public static void printMatrix(final int size, final int[] matrix) {
            for (int y = 0; y < size; y++) {
                for (int x = 0; x < size; x++) {
                    System.out.print(matrix[x + y * size]);
                    System.out.print(" ");
                }
                System.out.println();
            }
        }
    
        public static void printStatistics(final int size, final int count) {
            final int sumMatrix[] = new int[size * size];
            for (int i = 0; i < count; i++) {
                final int[] matrix = generate(size);
                for (int j = 0; j < sumMatrix.length; j++) {
                    sumMatrix[j] += matrix[j];
                }
            }
            printMatrix(size, sumMatrix);
        }
    
        public static void checkAlgorithm() {
            final int size = 8; 
            final int count = 2215764;
            final int divisor = 122;
            final int sumMatrix[] = new int[size * size];
            for (int i = 0; i < count/divisor ; i++) {
                final int[] matrix = generate(size);
                for (int j = 0; j < sumMatrix.length; j++) {
                    sumMatrix[j] += matrix[j];
                }
            }
            int total = 0;
            for(int i=0; i < sumMatrix.length; i++) {
                total += sumMatrix[i];
            }
            final double factor = (double)total / (count/divisor);
            System.out.println("Factor=" + factor + " (theory=16.0)");
        }
    
        public static void benchmark(final int size, final int count,
                final boolean parallel) {
            final long begin = System.currentTimeMillis();
            if (!parallel) {
                for (int i = 0; i < count; i++) {
                    generate(size);
                }
            } else {
                IntStream.range(0, count).parallel().forEach(i -> generate(size));
            }
            final long end = System.currentTimeMillis();
            System.out.println("rate="
                    + (double) (end - begin) / count + "ms/matrix");
        }
    
        public static void main(String[] args) {
            checkAlgorithm();
            benchmark(8, 10000, true);
            //printStatistics(8, 2215764/36);
            printStatistics(8, 2215764);
        }
    }
    

    The output is:

    Factor=16.0 (theory=16.0)
    rate=0.2835ms/matrix
    552969 554643 552895 554632 555680 552753 554567 553389 
    554071 554847 553441 553315 553425 553883 554485 554061 
    554272 552633 555130 553699 553604 554298 553864 554028 
    554118 554299 553565 552986 553786 554473 553530 554771 
    554474 553604 554473 554231 553617 553556 553581 553992 
    554960 554572 552861 552732 553782 554039 553921 554661 
    553578 553253 555721 554235 554107 553676 553776 553182 
    553086 553677 553442 555698 553527 554850 553804 553444
    

提交回复
热议问题