数独回溯 无效数独
Posted
技术标签:
【中文标题】数独回溯 无效数独【英文标题】:Sudoku Backtracking Non valid Sudoku 【发布时间】:2013-02-27 22:47:16 【问题描述】:我创建了一个数独回溯求解器,它工作得很好, 但是现在如果数独由于无效而无法解决,我想给出一个错误 例如,如果给出这个数独:
http://img5.imageshack.us/img5/2241/sudokugq.jpg
如果我的解决方法无法解决,我该怎么做才能让我的解决方法出错? 我总是以零结尾或陷入循环。
public void solve( int row, int col ) throws Exception
// Throw an exception to stop the process if the puzzle is solved
if( row > 8 )
//Gelöst
// If the cell is not empty, continue with the next cell
if( sudo[row][col] != 0 )
next( row, col ) ;
else
// Find a valid number for the empty cell
for( int num = 1; num < 10; num++ )
if( checkHorizontal(row,num) == false && checkVertikal(col,num)== false&& checkBox(row,col,num)== false )
sudo[row][col] = num ;
// Delegate work on the next cell to a resudosive call
next( row, col ) ;
// No valid number was found, clean up and return to caller
sudo[row][col] = 0 ;
//Ruft solve für das nächste Feld auf
public void next( int row, int col ) throws Exception
if( col < 8 )
solve( row, col + 1 ) ;
else
solve( row + 1, 0 ) ;
【问题讨论】:
我在这里发现了一个丑陋的设计:solve
依赖于next
和next
依赖于solve
。
这有什么问题?
@LuiggiMendoza - 我见过比这更复杂的递归解决方案。尽管它很复杂,但我认为它也是解决方案的真正实现。此外 - next
只是选择下一个要尝试的坐标。
是的,但这并不能解决我的问题。我的问题是:如果有一个无效的数独(如图所示),我该怎么做才能给出错误并退出循环?
【参考方案1】:
当然,当您点击sudo[row][col] = 0 ;
代码时,您刚刚尝试完正方形中的每个值,但没有找到任何解决方案。当然,这就是您决定放弃无解决方案状态的关键。
进一步考虑 - 我怀疑我几乎是对的。如果您点击此代码并且这是您正在尝试的第一个单元格(即您找到的第一个空单元格),那么这就是您的失败时刻。
顺便说一句 - 我不确定使用 Exception 来指示您在评论中建议的解决方案是否是个好主意。
这现在正确地拒绝了您发布的板 - 请注意,不仅第一行有两个“3”,而且第一列还有两个“5”。这段代码现在似乎对我有用。也许你可以在一个不溶的上试一试。
public class Test
static final int S = 9;
int[][] sudo;
public Test()
// Just leave it empty.
sudo = new int[S][S];
public Test(int[][] sudo)
this.sudo = sudo;
// This number should not appear anywhere in the row.
public boolean checkHorizontal(int row, int num)
for (int i = 0; i < S; i++)
if (sudo[row][i] == num)
return false;
return true;
// This number should not appear anywhere in the col.
public boolean checkVertical(int col, int num)
for (int i = 0; i < S; i++)
if (sudo[i][col] == num)
return false;
return true;
// This number should not appear anywhere in the box.
private boolean checkBox(int row, int col, int num)
// Round down to nearest 3.
int r = (row / 3) * 3;
int c = (col / 3) * 3;
for (int i = r; i < r + 3; i++)
for (int j = c; j < c + 3; j++)
if (sudo[i][j] == num)
return false;
return true;
boolean check(int row, int col, int num)
// All checks must pass.
return checkHorizontal(row, num)
&& checkVertical(col, num)
&& checkBox(row, col, num);
public boolean solve(int row, int col)
// Got to the end?
if (row >= S)
//Gelöst
return true;
// If the cell is empty
if (sudo[row][col] == 0)
// Find a valid number for the empty cell
for (int num = 1; num < 10; num++)
// Can this number be put there?
if (check(row, col, num))
// Yes!
sudo[row][col] = num;
// Try that.
if (next(row, col))
return true;
// Clean up.
sudo[row][col] = 0;
else
// Move on.
if (next(row, col))
return true;
// Failed to find a solution.
return false;
//Ruft solve für das nächste Feld auf
public boolean next(int row, int col)
if (col < S - 1)
// Step right.
return solve(row, col + 1);
else
// Step down.
return solve(row + 1, 0);
public boolean boardOk()
// Initial test to ensure it is a valid array.
// Must have that many rows.
boolean ok = sudo.length == S;
for (int row = 0; ok && row < S; row++)
// Each row must be that long.
ok &= sudo[row].length == S;
for (int col = 0; ok && col < S; col++)
// Each filled square must be valid.
if (sudo[row][col] != 0)
int num = sudo[row][col];
// Remove it.
sudo[row][col] = 0;
// Check it can be added.
ok &= check(row, col, num);
// Put it back.
sudo[row][col] = num;
return ok;
void solve()
if (boardOk())
boolean solved = solve(0, 0);
if (solved)
System.out.println("Solved!");
print();
else
System.out.println("Insoluble!");
print();
public void print()
for (int i = 0; i < sudo.length; i++)
System.out.println(Arrays.toString(sudo[i]));
/**
* @param args the command line arguments
*/
public static void main(String[] args)
new Test().solve();
int[][] test =
0, 0, 6, 5, 8, 3, 3, 2, 7,
0, 0, 0, 0, 9, 0, 0, 5, 0,
5, 8, 0, 0, 0, 0, 0, 0, 3,
0, 3, 1, 0, 4, 0, 5, 0, 0,
0, 0, 0, 9, 2, 0, 3, 0, 6,
0, 0, 0, 0, 0, 0, 0, 0, 1,
3, 4, 2, 0, 0, 6, 9, 1, 5,
5, 0, 5, 4, 0, 9, 0, 3, 2,
0, 1, 0, 0, 0, 0, 0, 0, 4,;
new Test(test).solve();
【讨论】:
不,sudo[row][col] = 0;只是表示它倒退了一步 我不明白您所说的“这是您尝试的第一个单元格”的意思,您能解释一下吗?对不起,如果这听起来很愚蠢,英语不是我的母语 不傻 - 给我几分钟 - 我正在尝试一些东西。 :) 你在数独板上错过了一个 3,一个 3 没问题,因为它是有效的。但是一排有 2 个 3 是无效的,所以它不能工作 已编辑代码 - 请重试 - 实际上您发布的电路板存在两个问题。第一列还有两个“5”。以上是关于数独回溯 无效数独的主要内容,如果未能解决你的问题,请参考以下文章