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

时间:2018-08-21 06:51:26

标签: java algorithm sudoku

这更多是一个逻辑问题。问题是:

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

  1. 任何数字都不能在行中重复
  2. 列中不得重复输入数字
  3. 矩阵的范围从3X3到8X8
  4. 矩阵应包含不按特定顺序排列的随机数

我不擅长将我尝试过的逻辑放在下面:

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;
}
}

当我打印二维数组时,我在某些地方看到值仍然为0。好像我的代码中断了。在某些时候,没有剩余的随机数可以填充。输出类似于:

enter image description here

我知道我的算法是不对的,我只是找不到方法来完成它。 我可以在这方面寻求帮助吗?

5 个答案:

答案 0 :(得分:3)

我已经保存并修改了一些代码,以便在需要其他时间时使用。我想这是给你的;)

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 

答案 1 :(得分:1)

在启动过程中定义以下矩阵:

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矩阵时,请执行以下操作:

  1. 从0-8之间随机选择N个数字(无重复)-> R
  2. 随机选择N个0到8之间的数字(不重复)作为列号-> C
  3. 最终矩阵的元素将为M [x] [y] = O [R [x]] [C [y]]

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

答案 2 :(得分:1)

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

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

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;
    }
}

输出:

4139562
1896375
2613857
9357124
6245931
3482619
8761493

答案 3 :(得分:0)

给它一个疯狂的镜头,而不是编写代码。但请仔细考虑:

如何开始逐列填充数字,例如

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

以此类推。

所以它精确地按顺序和对角线填充数字。

答案 4 :(得分:0)

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

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;
}

在某些情况下,更改最后一行不足以保证矩阵将被填充。这就是为什么我添加了一个计数器,如果通过更改最后一行找不到解决方案,它将重置整个矩阵。