简单的数独求解方法

时间:2011-05-21 09:09:57

标签: java algorithm sudoku


  

注意:此问题已解决,   实际问题不在于此   方法,但另一方,所以如果你   寻找有关数独的东西,最后   进入这个页面,你绝对可以   使用我的方法,它有效。


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

该方法是遍历板上的每个单元并填充所有只有1种可能性的单元。重复直到每个单元格都填满。很简单,这里是我的代码,返回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种可能性,这对于循环来说是不可能完成的。

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

5 个答案:

答案 0 :(得分:3)

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

 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。用它来检测你的算法是否发现了某些东西(如果没有,就会挽救)。

答案 1 :(得分:3)

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

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

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

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

你应该使用一个递归函数,只有当所有单元格都被填满时才会完成。

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

答案 4 :(得分:1)

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++;
                }
            }
        }
    }
}