【发布时间】:2015-11-05 18:43:55
【问题描述】:
我编写了一个回溯算法来生成任意大小的数独。我的问题是这个生成算法的速度变化。
我添加了一些控制台输出来查看结果。我生成了大约 20 个数独,大小为 16x16,每个数独的生成时间为 1 毫秒到 150 毫秒。下一个花了10多分钟,甚至没有完成。 (我停止了程序)。考虑到这一点,我认为我在回溯实现中犯了一个错误,导致算法无法前进。
代码如下:
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));
}
}
}
}
代码说明:
boolean[][][] 轨道:
已经尝试过的值的某种清单(以减少多次尝试相同随机值的开销)。如果我已经尝试将 val 放在该字段上,我将 track[row][col][val] 放在 true 上。如果我回去,我必须清除该单元格的标记,以使值再次成为可能。
ns.checkValue:
在单元格上设置值,检查数独是否仍然正确,再次设置旧值并返回真/假。
ns.setValue:
只需在单元格上设置值。
值:
包含尚未对该单元格尝试的值的数组列表。如果我继续前进,列表显然必须包含所有可能的数字。 如果我回溯,列表只需要包含尚未尝试的数字。 (我使用轨道数组来实现这一点)。
我做错了什么?
问候
【问题讨论】:
-
你可能想把它发到codereview。
-
在我早期的编程生涯中,我也尝试过制作一个预填充数独程序,首先你需要分析一个完全填充数独的所有可能规则,你会发现仅仅回溯是不够的,并且这就是为什么有时程序永远不会完成的原因,我也面临同样的情况......
标签: java algorithm performance sudoku