Sudoku generation speed

依然范特西╮ 提交于 2019-12-12 02:48:06

问题


I wrote a backtracking algorithm to generate sudokus with arbitrary size. My problem is the varying speed of this generation algorithm.

I added some console output to see the results. I generated ~20 Sudokus with the size of 16x16, each one had 1ms to 150ms generating time. The next one took over 10 minutes, and it didn't even finish. (I stopped the program). In consideration of that, I think I made a mistake in the backtracking implementation, which prevents the algorithm from advancing.

Here is the code:

public class Generator {
    public static NormalSudoku generateNormal(int size) {
    NormalSudoku ns = new NormalSudoku(size);
    boolean[][][] track = new boolean[size][size][size];
    ArrayList<Integer> vals = new ArrayList<Integer>();
    fill(vals, size);

    int row = 0;
    int col = 0;
    int val = 0;

    int count = 0;
    while (row < size) {
        boolean found = false;
        while (!vals.isEmpty() && !found) {
            val = vals.get((int) (Math.random() * vals.size()));
            track[row][col][val - 1] = true;
            if (ns.checkValue(row, col, val)) {
                 ns.setValue(row, col, val);
                 fill(vals, size);
                 col++;
                found = true;
            } else {
                 vals.remove(Integer.valueOf(val));
            }

            if (col >= size) {
                 row++;
                 col = 0;
            }
        }
        if (vals.isEmpty()) {
        ns.setValue(row, col, 0);
        for (int i = 0; i < size; i++) {
            track[row][col][i] = false;
        }
        col--;
        if (col < 0) {
            row--;
            col = size - 1;
        }
        ns.setValue(row, col, 0);
        fill(vals, track, row, col);
        }
    }
    return ns;
    }

    private static void fill(ArrayList<Integer> vals, int size) {
    vals.clear();
    for (int i = 1; i <= size; i++) {
        vals.add(i);
    }
    }

    private static void fill(ArrayList<Integer> vals, boolean[][][] track,
        int row, int col) {
    vals.clear();
    for (int i = 0; i < track[row][col].length; i++) {
        if (!track[row][col][i]) {
        vals.add(Integer.valueOf(i + 1));
        }
    }
    }
}

Explanation of the code:

boolean[][][] track:

some sort of checklist for the values which are already tried (to reduce overhead of trying the same random value multiple times). I put track[row][col][val] on true if I already tried to put val on this field. If I go back, I have to clear the marks for that cell, to make the values possible again.

ns.checkValue:

Sets the value on the cell, checks if the sudoku is still correct, sets the old value again and returns true/false.

ns.setValue:

Simply sets the value on the cell.

vals:

An array list containing the values which are not tried yet for that cell. If I move forward, the list obviously must contain every possible number. If I backtrack, the list only has to contain the numbers which aren't tried yet. (I use the track array to realize that).

What am I doing wrong?

Greets


回答1:


Ok first thing for some reason you chose a random number from vals list which most of the time is full with 10+ numbers, so you lose quite alot of time there. I tested your code and it really is quite random about the duration of the solving. For instance on this temporary solving

[12, 9, 14, 7, 5, 13, 8, 2, 15, 3, 4, 6, 16, 1, 10, 11]
[1, 2, 13, 15, 12, 16, 14, 4, 11, 8, 10, 9, 5, 6, 0, 0]
....

It takes too much time to fill cells (2,15) and (2,16) becouse it chooses a random from list vals with 10 values available for some reason but the possible values are numbers 3 and 7.

In the vals list you should exclude numbers from the current row and current column and region.

However this does not improve much the algorithm.

Your algorith is:

1. For current cell try all values until you find one that fits.
2. If it fits track it and move on to next cell.
3. If no value fits take step back, try value on the previous cell that was not used yet.

Becouse of the randomness your taking too much time on point 3 if some value is not on good place in some very first positions.



来源:https://stackoverflow.com/questions/33552365/sudoku-generation-speed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!