Java 用随机数填充矩阵,不垂直或水平重复

Java 用随机数填充矩阵,不垂直或水平重复,java,algorithm,sudoku,Java,Algorithm,Sudoku,这是一个更符合逻辑的问题。问题是: 我需要用数字(1-9)填充矩阵,以便: 第行中不应重复任何数字 列中不应重复任何数字 矩阵可以是3X3到8X8 矩阵应该包含非特定顺序的随机数 我不擅长逻辑,我试过的是: public class RandMatrix { static int max=8; static ArrayList<Integer> numbers=new ArrayList<>(); static int[][] arr=new int[max][max]

这是一个更符合逻辑的问题。问题是:

我需要用数字(1-9)填充矩阵,以便:

  • 第行中不应重复任何数字
  • 列中不应重复任何数字
  • 矩阵可以是3X3到8X8
  • 矩阵应该包含非特定顺序的随机数
  • 我不擅长逻辑,我试过的是:

    public class RandMatrix {
    static int max=8;
    static ArrayList<Integer> numbers=new ArrayList<>();
    static  int[][] arr=new int[max][max];
    public static void main(String[] a){
        // To fill number
        for (int i = 1; i <=9; i++) {
            numbers.add(i);
        }
        // Shuffle number
        Collections.shuffle(numbers);
        call();
    }
    
    public static void call(){
        for (int i = 0; i < max; i++) {
            for (int j = 0; j <max ; j++) {
                for (int k = 0; k <max ; k++) {
                    int num=numbers.get(k);
                    if(!isExist(num,i,j)){
                        arr[i][j]=num;
                        break;
                    }
                }
            }
            Collections.shuffle(numbers);
        }
    }
    
    private static boolean isExist(int num,int row, int col){
        for (int i = row; i >=0; i--) {
            if(arr[i][col]==num){
                return true;
            }
        }
        for (int j = col; j >=0; j--) {
            if(arr[row][j]==num){
                return true;
            }
        }
        return false;
    }
    }
    
    公共类矩阵{
    静态int max=8;
    静态ArrayList编号=新ArrayList();
    静态int[]arr=新int[max][max];
    公共静态void main(字符串[]a){
    //填
    
    对于(inti=1;i给它一个疯狂的机会,不是写代码,而是思考:

    开始按列填写数字,这样可以吗

    mat[0][0]=1
    
    mat[1][0]=2
    
    ...
    
    mat[8][0]=9
    
    然后,开始填充下一列时,请执行以下操作:

    mat[1][1]=1
    
    mat[2][1]=2
    
    ...
    
    mat[8][1]=8
    
    mat[0][1]=9
    
    等等


    因此,它精确地按顺序和对角线填充数字。

    使用纯随机填充矩阵,如果到达死角,则需要重做结果的最后一部分

    public static void call(){
        int repeats = 0;
        for (int i = 0; i < max; i++) {
            for (int j = 0; j <max ; j++) {
                for (int k = 0; k <max ; k++) {
                    int num=numbers.get(k);
                    if(!isExist(num,i,j)){
                        arr[i][j]=num;
                        break;
                    }
                }
            }
            if(containsZero(arr[i]){
                i--;
                repeats++;
                if(repeats > 1000){
                    i = 0;
                    repeats = 0;
                }
            }
            Collections.shuffle(numbers);
        }
    }
    private static boolean containsZero(int[] array){
        for(int i = 0; i < array.length; i++){
            if(array[i] == 0){
                return true;
            }
        }
        return false;
    }
    
    publicstaticvoid调用(){
    int repeats=0;
    对于(int i=0;i对于(int j=0;j在启动期间定义以下矩阵:

    1 2 3 4 5 6 7 8 9
    2 3 4 5 6 7 8 9 1
    3 4 5 6 7 8 9 1 2
    4 5 6 7 8 9 1 2 3
    5 6 7 8 9 1 2 3 4
    6 7 8 9 1 2 3 4 5
    7 8 9 1 2 3 4 5 6
    8 9 1 2 3 4 5 6 7
    9 1 2 3 4 5 6 7 8
    
    需要创建n X n矩阵时,请执行以下操作:

  • 随机选取0-8之间的N个数字(不重复)作为行号->R
  • 为列编号->C随机选择0-8(无重复)之间的N个数字
  • 最终矩阵的元素将是M[x][y]=O[R[x]][C[y]]

  • 唯一的问题是结果仍然不是完全随机的。(它不能生成所有可能的解决方案。)尽管随机性仅在标题中提到,但在3个要求中没有提到…

    我认为最好的方法是使用随机回溯算法

    矩阵的元素一个接一个地填充。对于每个矩阵元素,我们首先枚举所有可以使用的剩余整数(基于前面的元素)。然后以随机顺序尝试每个整数,直到找到第一个解

    public static void main(String[] args) {
        int[][] matrix = getMatrix(7, 0L);
        if (matrix != null) {
            for (int row = 0; row < 7; ++row) {
                for (int column = 0; column < 7; ++column) {
                    System.out.print(matrix[row][column]);
                }
                System.out.println();
            }
        }
    }
    
    
    public static int[][] getMatrix(int size, long seed) {
        int[][] matrix = new int[size][size];
        Random random = new Random(seed);
        if (!backtrack(matrix, size, 0, random))
            return null;
        return matrix;
    }
    
    // returns true when the backtracking could succesfully fill the matrix
    private static boolean backtrack(int[][] matrix, int size, int index, Random random) {
        if (index == size * size) {
            // all elements are filled without conflict
            return true;
        } else {
            // find the row and column of the next element which need to be filled
            int column = index % size;
            int row = index / size;
    
            // an array which indicates whether the numbers in range [1 - 9] can be used
            // canUse[x] encodes whether number (x+1) can be used
            boolean[] canUse = new boolean[9];
            Arrays.fill(canUse, true);
    
            // check the previous rows and column elements
            for (int c = 0; c < column; ++c)
                canUse[matrix[row][c] - 1] = false;
            for (int r = 0; r < row; ++r)
                canUse[matrix[r][column] - 1] = false;
    
            // generate the list of possible entries
            List<Integer> possibilities = new ArrayList<Integer>();
            for (int i = 1; i <= 9; ++i)
                if (canUse[i - 1])
                    possibilities.add(i);
    
            // backtrack if there are no possible entries
            if (possibilities.isEmpty())
                return false;
    
            // shuffle the list (to randomly fill the matrix)
            Collections.shuffle(possibilities, random);
    
            // enter the number
            for (int possiblity : possibilities) {
                matrix[row][column] = possiblity;
    
                if (backtrack(matrix, size, index + 1, random))
                    return true;
            }
    
            return false;
        }
    }
    

    我刚才保存并修改了一些代码,以便在需要其他时间时使用。我想这是为您准备的;)


    更简单的方法是首先编写一个明显满足要求的数组(例如
    [[1,2,3],[3,1,2],[2,3,1]]
    )然后随机交换行,随机交换列。
    这显然满足了要求
    这将是硬编码的。这种安排是一种数独游戏,所以我认为你的建议可能是正确的。因为只有一些解决方案可以按照你的方式使用。但我需要在运行时填充数组。那么我如何填充我不能满足要求?这是我的问题。我想不出一个办法。我需要一个数学天才给我一些指导,但我肯定不是。这几乎很好。但这样的数字不会是随机的。我列出的方法(最终)生成满足条件的所有数组,其“随机性”与尝试按数字填充数组一样。@HighPerformanceMark您的方法对我来说有意义。请尝试一下。建议使用Thx。我不认为先填充collum会有任何区别。无论如何,我会尝试一下。您测试过吗?关键在于此,
    因此,精确地按顺序和对角线填充数字
    。按列或按行填充并不重要。用笔和纸就足够了:)是的,你说对了,死胡同是我的问题。我会试试你的解决方案。好吧。那太令人印象深刻了。我会深入研究你的代码。会马上回来。谢谢。@ADM我只是想知道数独和这个问题之间是否有关系??
    4139562
    1896375
    2613857
    9357124
    6245931
    3482619
    8761493
    
    import java.util.Arrays;
    import java.util.Random;
    
    class Test {
        public static void main(String[] args){
            int size = 9;
    
            int[][] matrix= new int[size][];
            matrix[0] = MatrixOps.createOrderedArray(size, 1);
    
            for(int x=0; x < size; x++) {
                matrix[x] = MatrixOps.createOrderedArray(size, 1);
                do {
                    MatrixOps.shuffle(matrix[x]);
                } while(! MatrixOps.compare2DArray(matrix[x], matrix, 0, x));
            }
            MatrixOps.print(matrix);
        }
    }
    
    class MatrixOps {
    
        public static void shuffle(int[] arr){
            Random random = new Random();
            for(int x = 0; x < arr.length; x++)
                swap(arr, x, random.nextInt(arr.length));
        }
    
        public static int[] createOrderedArray(int size, int startValue) {
            int[] num = new int[size];
            for (int x = 0; x < num.length; x++)
                num[x] = x + startValue;
            return num;
        }
    
        public static boolean compare2DArray(int[] arr1, int[][] arr2, int begin, int end) {
            for (int x = begin; x < end; x++)
                if (!compareArray(arr1, arr2[x]))
                    return false;
            return true;
        }
    
        // https://stackoverflow.com/questions/19648240/java-best-way-to-print-2d-array/41533179#41533179
        public static void print(int[][] array) {
            for (int[] x: array) {
                for (int y: x) {
                    System.out.print(y + " ");
                }
                System.out.println();
            }
        }
    
        private static boolean compareArray(int[] arr1, int[] arr2){
            if(arr1.length != arr2.length)
                return false;
            for(int x=0; x<arr1.length; x++)
                if(arr1[x] == arr2[x])
                    return false;
            return true;
        }
    
        private static void swap(int[] arr, int a, int b){
            int temp = arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }
    }
    
    5 1 7 2 3 8 9 4 6 
    4 3 1 5 7 9 2 6 8 
    9 7 3 8 6 2 4 5 1 
    6 8 4 3 5 7 1 9 2 
    1 5 8 9 2 6 7 3 4 
    7 9 2 6 4 1 5 8 3 
    8 6 9 4 1 5 3 2 7 
    3 2 6 7 9 4 8 1 5 
    2 4 5 1 8 3 6 7 9