我寫了一個回溯算法來生成任意大小的數獨。我的問題是這一代算法的變化速度。數獨生成速度
我添加了一些控制檯輸出來查看結果。我生成了大小爲16x16的〜20 Sudokus,每個生成時間爲1ms到150ms。下一個花了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));
}
}
}
}
的代碼的說明:
布爾[] [] []磁道:
某種清單爲它們已經嘗試過的值(以減少多次嘗試相同的隨機值的開銷)。如果我已經嘗試將val放在這個字段上,我將track [row] [col] [val]設置爲true。如果我回去,我必須清除那個單元格的標記,以使這些值再次可能。
ns.checkValue:
設置在單元格的值,會檢查數獨仍然是正確的,再次將舊的值,並返回真/假。
ns.setValue:
只需設置單元格上的值。
瓦爾斯:
含有不用於該小區還嘗試過的值的數組列表。如果我繼續前進,那麼列表顯然必須包含每個可能的數字。 如果我回溯,列表只需包含尚未嘗試的數字。 (我使用軌道陣列來實現這一點)。
我在做什麼錯?
電賀
您可能想將其發佈到[codereview](http://codereview.stackexchange.com/)。 – 2015-11-05 18:47:28
我也嘗試在編程初期做一個預填數獨程序,首先你需要分析一個完全填充的數獨的所有可能的規則,你會發現單獨的回溯是不夠的,這就是爲什麼有時程序從不完成後,我也面臨同樣的情況... –