11

我的逻辑求解算法有问题。它很好地解决了具有大量提示的谜题,它只是对少于 45 条线索的谜题有问题。

这是求解的算法。Immutable 是一个布尔值,用于确定该值是否可以更改。cell[row][col].possibleValues 是一个名为 SudokuCell 的类中的 LinkedList,它存储该网格元素的可能值。grid.sGrid 是拼图的主要 int[][] 数组。removeFromCells() 是一种从网格的行、列和象限中删除值的方法。该代码在下面提供。

第二个 for 循环仅用于检查单个解决方案。我决定避免递归,因为我真的无法理解它。这种方法目前似乎运行良好。

public boolean solve(){

    for(int i = 0; i < 81; i++){
        for(int row = 0; row < 9; row++){
            for(int col = 0; col < 9; col++){
                if(!immutable[row][col]){
                    if(cell[row][col].getSize() == 1){
                        int value = cell[row][col].possibleValues.get(0);
                        grid.sGrid[row][col] = value;
                        immutable[row][col] = true;
                        removeFromCells(row, col, value);
                    }
                }
            }
        }
    }


    int i = 0;
    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            if(grid.sGrid[row][col] == 0){
                i++;
            }
        }
    }

    if(i != 0){
        return false;
    } else{
        return true;
    }
}

这是 removeFromCells() 的代码

我认为大部分代码都是不言自明的。第一个 for 循环从 (x, y) 的行和列中删除值,第二个循环从象限中删除值。

public void removeFromCells(int x, int y, int value){

    /*
     * First thing to do, find the quadrant where cell[x][y] belong.
     */

    int topLeftCornerRow = 3 * (x / 3) ;
    int topLeftCornerCol = 3 * (y / 3) ;

    /*
     * Remove the values from each row and column including the one
     * where the original value to be removed is.
     */
    for(int i = 0; i < 9; i++){
        cell[i][y].removeValue(value);
        cell[x][i].removeValue(value);
    }


    for(int row = 0; row < 3; row++){
        for(int col = 0; col < 3; col++){
            cell[topLeftCornerRow + row][topLeftCornerCol + col].removeValue(value);
        }
    }
}

另一个问题点可能是构造可能值的位置。这是我的方法:

第一个 for 循环创建新的 SudokuCells 以避免可怕的空指针异常。

sGrid 中的任何空值都表示为 0,因此 for 循环会跳过这些值。

SudokuBoard 的构造函数调用了这个方法,所以我知道它被调用了。

public void constructBoard(){

    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            cell[row][col] = new SudokuCell();
        }
    }

    immutable = new boolean[9][9];

    for(int row = 0; row < 9; row++){
        for(int col = 0; col < 9; col++){
            immutable[row][col] = false;
            if(grid.sGrid[row][col] != 0){
                removeFromCells(row, col, grid.sGrid[row][col]);
                immutable[row][col] = true;
            }
        }
    }
}

我会发布整个文件,但是那里有很多不必要的方法。我发布了我认为导致我的问题的内容。

4

2 回答 2

6

您现在似乎只构建了一个基于简单约束的解决方案。你需要一个完整的回溯,以便用更少的提示来解决难题。有些情况如果不回溯就无法真正解决。

或者,您应该尝试实施 Knuth 算法(Dancing Links)来解决此类问题。理解和实现比回溯算法更复杂,但它的运行方式更好:)。见这里:http ://en.wikipedia.org/wiki/Dancing_Links

它也是解决更一般问题的算法,并且非常成功地应用于解决数独问题。

在维基百科上有一篇文章的链接,详细说明了使用约束编程可以解决哪些类型的实例:http: //4c.ucc.ie/~hsimonis/sudoku.pdf(可从此处找到:http://en.wikipedia .org/wiki/Sudoku_algorithms)。表 4 真的很有趣 :)。

于 2011-03-08T18:59:21.793 回答
2

我使用了许多这样的规则来开发我的数独求解器。然而,我总是被迫对非常难的数独使用回溯。根据维基百科,仅使用规则实际上不可能解决一些数独问题。

我一共实施了6条规则。

  1. 不允许其他值..
  2. 同一部分的其他方格中不允许有某个值。
  3. 在同一行或同一列的其他方格中不允许有某个值。
  4. 某个值只允许在一个部分内的一列或一行上,因此我们可以从其他部分的该行或列中消除该值。
  5. 裸对
  6. 线条

我在这两篇博文中描述了整个算法并给出了代码(初始版本只使用了前 4 条规则)。

http://www.byteauthor.com/2010/08/sudoku-solver/

http://www.byteauthor.com/2010/08/sudoku-solver-update/

PS。我的算法倾向于性能,因此它会自动平衡回溯与这些规则,即使它有时可以在没有任何猜测的情况下完成。

于 2011-04-30T22:13:31.407 回答