繁体   English   中英

简单的数独求解方法

[英]Simple Sudoku solving method


注意:这个问题已经解决了,实际问题不是在这个方法而是另一个,所以如果你正在寻找关于数独的东西并最终进入这个页面,你绝对可以使用我的方法,它可以工作。


好的,忘记用于解决数独的所有复杂算法。 我正在编写一个简单的Java解算器来解决简单的数独游戏。 这种方法的想法非常普遍,所以我想每个人都已经知道了。 我也很惊讶我无法完成它。

该方法是遍历板上的每个单元并填充所有仅具有一种可能性的单元。 重复直到每个单元格都填满。 很简单,这里是我的代码,返回int数量可以填充:

public int solveGame() {

/*
 variable possible contains 10 elements, the first element is true if there 
 is one or more possible value to fill in, false otherwise. The remaining 
 elements (1-9) are whether true or false depending on their indexes 
 e.g. possible[3] is true if 3 is a possibility.
*/
boolean[] possible; 

int[] save;
int count;
int numresolve = 0;

while (!isFinished()) {

    for (int i = 0; i < GAMESIZE; i++) {
        for (int j = 0; j < GAMESIZE; j++) {
            possible = new boolean[10];
            possible = getPossible(i,j);
            if (possible[0]) {
                count = 0;
                save = new int[9];
                for (int k = 1; k < 10; k++) {
                    if (possible[k]) {
                        count++;
                        save[count] = k;
                    }
                }
                if (count == 1) {
                    setCell(i,j,save[count]);
                    numresolve++;
                }
            }
        }
    }
}

return numresolve;

}

我的代码的问题是它永远无法完成循环,因为在填充所有具有1种可能性的单元格之后,剩余的单元格将具有多于1种可能性,这对于循环不可能完成。

我知道我错过了一些我无法想到的东西。

要检测到使用此方法无法解决任何问题,请执行以下操作:

 while (!isFinished()) {
   int prevResolved = numresolve;

   .... // your loop

   if (numresolve == prevResolved) {
     // did not find anything - out of luck, can't solve this board.
     return ...; // numresolve or something to indicate that it failed
   }
}

如果你的算法在一个循环中没有发现任何东西,那么它并没有改变电路板 - 所以下一次它将找不到任何其他东西。

或者,只需在循环顶部将布尔值设置为false ,并在对板进行更改时将其设置为true 用它来检测你的算法是否发现了某些东西(如果没有,则进行拯救)。

我没有看到这个代码有什么问题,除了无法检测到你无法解决这个难题。 你将能够解决的sudokus的难度显然取决于你的getPossible的实现,它没有发布。
请记住,即使是“非常容易”的sudokus也可能包括你必须同时分析多个细胞的部分,如果你不能在getPossible中做到这一点,你将无法解决任何问题:

考虑单元格1 == {a,b},单元格2 = {a,b},单元格3 = {a,b,c}

细胞3是可以解决的,这种情况很可能发生在你将要在书中找到的最简单的sudokus等。

您可能想要做的是在您的算法不再能够解析更多单元格之后查看该板,然后找出缺少的逻辑将使您的算法能够解决更多单元格。

如果填写单元格(通过调用setCell ),则减少同一行/列/块中所有其他单元格的可能性。 检查您的例程getPossibile考虑了这些更改。

另请注意,使用简单策略无法解决某些难题。 可能存在每个开放单元允许多于一个值的情况,但总而言之,存在唯一的解决方案。

您应该使用递归函数,该函数仅在填充了所有单元格时才会完成。

会发生没有单元只有一种可能性,所以你的代码应该通过再次调用函数本身来分叉两种(或多种)可能性,直到网格完全填满。

int numresolve = 0;

// this variable will be used to track # of changed cells in each loop
// init to -1 to run loop at least once
// loop can be more elegant if you put the condition at the end
int changed = -1;

// stop loop if no cell changed
while (!isFinished() && changed != 0) {

    // initialize # of changed cells in this loop    
    changed = 0;

    for (int i = 0; i < GAMESIZE; i++) {
        for (int j = 0; j < GAMESIZE; j++) {
            boolean[] possible = getPossible(i,j);
            if (possible[0]) {
                int count = 0;
                int[] save = new int[9];
                for (int k = 1; k < 10; k++) {
                    if (possible[k]) {
                        count++;
                        save[count] = k;
                    }
                }
                if (count == 1) {
                    setCell(i,j,save[count]);
                    numresolve++;
                    changed++;
                }
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM