确定数独是不是有唯一解

Posted

技术标签:

【中文标题】确定数独是不是有唯一解【英文标题】:Determine whether a Sudoku has a unique solution确定数独是否有唯一解 【发布时间】:2014-06-21 15:42:57 【问题描述】:

我正在努力使用回溯算法来确定数独是否有唯一的解决方案,或者它是否有多个解决方案。这是我使用的回溯代码:

    static boolean solve(int i, int j, int[][] cells) 
    if (i == 9) 
        i = 0;
        if (++j == 9)
            return true;
    
    if (cells[i][j] != 0)  // skip filled cells
        return solve(i+1,j,cells);

    for (int val = 1; val <= 9; ++val) 
        if (legal(i,j,val,cells)) 
            cells[i][j] = val;
            if (solve(i+1,j,cells))
                return true;
        
    
    cells[i][j] = 0; // reset on backtrack
    return false;

第一种方法: 如果我改变了

for (int val = 1; val <= 9; ++val) 
for (int val = 9; val >= 1; val--) 

我得到了两种不同的求解算法,它们应该找到不同的解决方案(如果存在不同的解决方案)。这种方法的问题是,即使只是轻微的变化,算法也不会终止,我不知道为什么。

第二种方法: 重置以回溯并继续寻找解决方案。如果我尝试这个,它也不起作用。

我试图找到一个 Java 示例,但我只能找到诸如“在回溯中重置并继续寻找第二个解决方案”之类的信息。

有人可以提供一个如何更改算法的示例,以便它告诉我是否存在多个解决方案(不需要确切的数字)

有人可以向我解释为什么我的第一种方法没有终止吗?

谢谢!

【问题讨论】:

“legal()”是什么意思?我正在尝试将这段代码翻译成 C.. 如果在位置 i、j 允许 val,则返回 true;如果在相应的行、列或 3x3 网格中存在相同的值,则返回 false 【参考方案1】:

如果您返回一个数字而不是布尔值,您可以区分存在 0、1 或多于 1 个解决方案的情况。

// returns 0, 1 or more than 1 depending on whether 0, 1 or more than 1 solutions are found
static byte solve(int i, int j, int[][] cells, byte count /*initailly called with 0*/) 
    if (i == 9) 
        i = 0;
        if (++j == 9)
            return 1+count;
    
    if (cells[i][j] != 0)  // skip filled cells
        return solve(i+1,j,cells, count);
    // search for 2 solutions instead of 1
    // break, if 2 solutions are found
    for (int val = 1; val <= 9 && count < 2; ++val) 
        if (legal(i,j,val,cells)) 
            cells[i][j] = val;
            // add additional solutions
            count = solve(i+1,j,cells, count));
        
    
    cells[i][j] = 0; // reset on backtrack
    return count;

【讨论】:

为什么使用字节?您期望最多 127 个解决方案?此外,AFAIK byteint 占用相同的内存,因此没有真正的区别。 @kajacx:只需要找到 2 个解决方案来判断,如果解决方案是唯一的,那么 为什么不 但是我看不到任何地方会检查解决方案的数量,所以如果数独有 256 个解决方案,那么您的方法将返回 0。 @kajacx:查看 for 循环中的条件。您是否认为我正在为所有解决方案进行 DFS? @kajacx:顺便说一句:如果没有填充任何字段,即使是 int 也会溢出,因为有超过 (9!)^3 &gt; 2^55 解决方案(应该可以独立填充一个对角线上的 3x3 字段)。 【参考方案2】:

重置必须在 for 循环内并且在 if solve 条件之后

 for (int val = 1; val <= 9; ++val) 
        if (legal(i,j,val,cells)) 
            cells[i][j] = val;
            if (solve(i+1,j,cells))
                return true;
            cells[i][j] = 0; // reset on backtrack
        
    

【讨论】:

谢谢,现在即使for循环倒计时而不是倒计时,算法也会终止。 两个答案都是正确的,可惜我只能接受一个。 @user3158988 谢谢,您可以为正确答案投票 :) 我只想知道为什么有人不赞成我的回答。但希望他/她发表评论

以上是关于确定数独是不是有唯一解的主要内容,如果未能解决你的问题,请参考以下文章

数独问题(Java版)

基于第二次数独游戏,添加GUI界面

洛谷 1784数独

数独(luogu 1784)

数独算法

洛谷P1784 数独