我正在为一门课程制作数独求解器,但是我的解决方法在solve方法上有问题。我目前的解决方法使用了递归回溯(我想)。
任务要求
int solve() -- 尝试使用上述策略解决谜题。返回解的数量。
(上述策略如下)
当给一个格子分配数字时,从不分配与该行、列或宫冲突的数字。我们事先小心地将合法数字分配给一个格子,而不是分配任何数字 1..9 并在递归中后来才发现问题。假设初始网格都是合法的,在此之后只进行合法的格子分配。
伪代码思路
对于小输入,我可以按迭代方式遵循这个策略。例如,假设我有两个未解决的单元格Cell#1和Cell#2。#1有可能性{1,3},#2有可能性{2,3}。然后我将会
set 1 to 1
set 2 to 2
hasConflicts? 0 : 1
set 2 to 3
hasConflicts? 0 : 1
set 1 to 3
set 2 to 2
hasConflicts? 0 : 1
set 2 to 3
hasConflicts? 0 : 1
实际代码
public int solve() {
long startTime = System.currentTimeMillis();
int result = 0;
if (!hasConflicts()) {
Queue<VariableCell> unsolved = getUnsolved();
reduceUnsolvedPossibilities(unsolved); // Gets the possibilities down from all of 1-9
if (!hasConflicts()) {
result = solveRec(unsolved);
}
}
mElapsedTime = System.currentTimeMillis() - startTime;
return result;
}
protected int solveRec(Queue<VariableCell> unsolved) {
if (unsolved.isEmpty()) {
return (hasConflicts()) ? 0 : 1;
}
int result = 0;
VariableCell cell = unsolved.remove();
Iterator<String> possibilityIt = cell.getPossibilities().iterator();
while (possibilityIt.hasNext()) {
cell.setSymbol(possibilityIt.next());
if (hasConflicts()) {
possibilityIt.remove();
} else {
++result;
}
}
return result + solveRec(unsolved);
}
测试结果
testSolveSingleSolution
expected 1, actual 1
testSolveSolved
expected 1, actual 1
testSolveUnsolvable
expected 0, actual 0
testSolveMultiSolutions
expected 2, actual 7 // MAJOR PROBLEM!
一些关于递归回溯的好解释
- 这个答案 来自StackOverflow - 数独生成器的递归解决方案
- 这个答案来自StackOverflow-迷宫中的BackTracking
- 这个答案来自StackOverflow - 素数序列的回溯算法
- 这个答案来自 StackOverflow - 如何只用这种回溯找到第一个解
- 维基百科文章 回溯法
- 递归回溯解释
问题
我以前做过递归回溯,我看了上面所有的链接以及更多内容,但我仍然有困难。我认为问题在于我的思考如何解决这个问题(请参见伪代码想法)。对于穷举搜索,使用递归回溯是否合适? 回溯是否正确但实现不正确? 是否有比递归回溯更好的算法?