回溯数独求解器不起作用
Posted
技术标签:
【中文标题】回溯数独求解器不起作用【英文标题】:Sudoku Solver by Backtracking not working 【发布时间】:2009-10-06 03:48:20 【问题描述】:假设一个二维数组包含一个 9x9 数独网格,我的求解函数在哪里崩溃?我正在尝试使用简单的回溯方法来解决这个问题。谢谢!
bool solve(int grid[9][9])
int i,j,k;
bool isSolved = false;
if(!isSolved(grid))
isSolved = false;
if(isSolved)
return isSolved;
for(i=0; i<9; i++)
for(j=0; j<9; j++)
if(grid[i][j] == 0)
for(k=1; k<=9; k++)
if(legalMove(grid,i,j,k))
grid[i][j] = k;
isSolved = solve(grid);
if (isSolved)
return true;
grid[i][j] = 0;
isSolved = false;
return isSolved;
即使更改了isSolved
问题,我的解决方案似乎也陷入了无限循环。看起来我错过了一些基本案例步骤,但我不确定在哪里或为什么。我已经查看了类似的解决方案,但仍然无法确定问题所在。我只是想创建基本的求解器,不需要提高效率。感谢您的帮助!
【问题讨论】:
错误是什么?像这样暴力破解数独谜题非常疯狂——第三个内部循环中的递归调用有一些疯狂的排列。 到底是什么问题?您发布了一堆代码,并问“我的功能在哪里中断?”。请描述哪些有效,哪些无效,为什么您无法修复它,以及您希望我们做什么。 【参考方案1】:是的,你的基本情况搞砸了。在递归函数中,基本情况应该在开始时处理。你有
bool isSolved = false;
if(!isSolved(grid))
isSolved = false;
if(isSolved)
return isSolved;
请注意,您的 isSolved 变量永远不能设置为 true,因此您的代码
if(isSolved)
return isSolved;
无关紧要。
即使你解决了这个问题,它也会感觉像是一个无限循环,即使它是有限的。这是因为您的算法每次调用求解时可能总共需要检查 9*9*9 = 729 个案例。输入此函数 n 次可能需要检查多达 729^n 个案例。显然不会检查很多案例,因为它会在放置非法时找到死胡同,但是谁说可能数字的 90% 的排列导致除了一个数字以外的所有数字都合法的情况?此外,即使您要平均检查 k 个案例,其中 k 是一个小数字(k
诀窍是“尝试”将数字放置在它们很可能成为实际良好位置的地方。可能我能想到的最简单的方法是约束满足求解器,或者具有启发式(如 A*)的搜索算法。
我实际上写了一个基于约束满足求解器的数独求解器,它可以在不到一秒的时间内解决 100x100 的数独问题。
如果奇迹般地“蛮力”回溯算法在 9x9 情况下对您很有效,请尝试更高的值,您会很快看到运行时间的恶化。
我不是在抨击回溯算法,事实上我喜欢它,它一次又一次地表明,如果正确实施回溯可以与动态编程一样有效,但是,在你的情况下,你没有实现它正确。你在暴力破解它,你不妨让你的代码非递归,它会完成同样的事情。
【讨论】:
你能分享你的 100x100 求解器吗?我真的不相信你怎么能在几秒钟内解决它!【参考方案2】:您将 isSolved 称为函数和布尔变量。 我不认为这是合法的,而且绝对不聪明。
您的函数的名称应该与您的变量不同。
【讨论】:
【参考方案3】:似乎无论这是否合法,您都将“0”分配给方格,即“grid[i][j] = 0;”线。也许你的意思是把“else”然后“grid[i][j] = 0;” ?
【讨论】:
不这么认为,只有当solve() 的递归调用没有返回true 时,才应该进行赋值,也就是说,将那个特定的值放在那个单元格中没有得到一个解决方案。在这种情况下,您想删除该值并尝试其他方法。以上是关于回溯数独求解器不起作用的主要内容,如果未能解决你的问题,请参考以下文章