一个酷炫的算法来检测数独场?

25

有没有人知道一个简单的算法来检查数独配置是否有效?我想到的最简单的算法是(对于大小为n的棋盘)伪代码如下:

有没有人知道一个简单的算法来检查数独配置是否有效?我想到的最简单的算法是(对于大小为n的棋盘)伪代码如下:

for each row
  for each number k in 1..n
    if k is not in the row (using another for-loop)
      return not-a-solution

..do the same for each column

但我相信一定有更好(更优雅的)解决方案。效率并不是非常重要。


在这里的所有算法中添加:检查没有数字比你的正方形边数更高。 - StriplingWarrior
25个回答

0
我会编写一个接口,其中包含接收数独字段并返回 true/false 是否为解决方案的函数。然后,按每个约束单独实现验证类。
验证时只需遍历所有约束类,并且当全部通过时数独才正确。为了加速验证过程,将最有可能失败的放在前面,在第一个指向无效字段的结果处停止。
这是一种非常通用的模式。 ;-)
当然,你可以增强它以提供哪些字段可能是错误的提示等。
第一个约束条件:仅检查是否填写了所有字段(简单循环);第二个约束条件:检查每个块中是否存在所有数字(嵌套循环);第三个约束条件:检查完整行和列(几乎与上述程序相同但访问方案不同)。

0
假设 int sudoku [0..8,0..8] 是数独场。
bool CheckSudoku(int[,] sudoku)
{
    int flag = 0;

// Check rows
for(int row = 0; row < 9; row++)
{
    flag = 0;
    for (int col = 0; col < 9; col++)
    {
        // edited : check range step (see comments)
        if ((sudoku[row, col] < 1)||(sudoku[row, col] > 9)) 
        {
            return false;
        }

        // if n-th bit is set.. but you can use a bool array for readability
        if ((flag & (1 << sudoku[row, col])) != 0) 
        {
            return false;
        }

        // set the n-th bit
        flag |= (1 << sudoku[row, col]); 
    }
}

// Check columns
for(int col= 0; col < 9; col++)
{
    flag = 0;
    for (int row = 0; row < 9; row++)
    {
        if ((flag & (1 << sudoku[row, col])) != 0)
        {
            return false;
        }
        flag |= (1 << sudoku[row, col]);
    }
}

// Check 3x3 boxes
for(int box= 0; box < 9; box++)
{
    flag = 0;
    for (int ofs = 0; ofs < 9; ofs++)
    {
        int col = (box % 3) * 3;
        int row = ((int)(box / 3)) * 3;

        if ((flag & (1 << sudoku[row, col])) != 0)
        {
            return false;
        }
        flag |= (1 << sudoku[row, col]);
    }
}
return true;

}


如果有人输入了一个无效的值(例如0或10),这个算法仍然会被评估为true。只是挑剔而已 :-) 可以通过在每个内部循环的末尾进行一次额外的测试来修复:flag xor 0x1FF = 0。 - malach
要说实话,这对于大于31的值也不起作用。我认为整个数独的值范围应该是一个单独的步骤。 - Marco M.
2
你不能仅考虑单个操作的实现和其运行的架构,就说O(3(n^2))比O(n^2)更好或更差;它们属于同一复杂度类。你需要检查3*n^2个数据。如果你在一个大循环中完成,或者分成三个小循环完成,这是相同的。 - Marco M.

0
array = [1,2,3,4,5,6,7,8,9]  
sudoku = int [][]
puzzle = 9 #9x9
columns = map []
units = map [] # box    
unit_l = 3 # box width/height
check_puzzle()    


def strike_numbers(line, line_num, columns, units, unit_l):
    count = 0
    for n in line:
        # check which unit we're in
        unit = ceil(n / unit_l) + ceil(line_num / unit_l) # this line is wrong - rushed
        if units[unit].contains(n): #is n in unit already?
             return columns, units, 1
        units[unit].add(n)
        if columns[count].contains(n): #is n in column already?
            return columns, units, 1
        columns[count].add(n)
        line.remove(n) #remove num from temp row
    return columns, units, line.length # was a number not eliminated?

def check_puzzle(columns, sudoku, puzzle, array, units):
    for (i=0;i< puzzle;i++):
        columns, units, left_over = strike_numbers(sudoku[i], i, columns, units) # iterate through rows
        if (left_over > 0): return false

没有经过彻底的检查,仅凭记忆,这应该可以(需要进行一些调试),同时只循环两次。时间复杂度为O(n^2),而不是O(3(n^2))。


如果我没记错的话,O(n^2) == O(3(n^2))吗? - Kami
@Kami 你没错。我甚至都不记得写过这个答案了。如果我能重来一次,我会采取完全不同的方法。有趣的是,在两年多的时间里你可以学到很多:P - Josh Smeaton

0

这是我的C语言程序。只能走一遍每个正方形。

int checkSudoku(int board[]) {
  int i;
  int check[13] = { 0 };

  for (i = 0; i < 81; i++) {
    if (i % 9 == 0) {
      check[9] = 0;
      if (i % 27 == 0) {
        check[10] = 0;
        check[11] = 0;
        check[12] = 0;
      }
    }

    if (check[i % 9] & (1 << board[i])) {
      return 0;
    }
    check[i % 9] |= (1 << board[i]);

    if (check[9] & (1 << board[i])) {
      return 0;
    }
    check[9] |= (1 << board[i]);

    if (i % 9 < 3) {
      if (check[10] & (1 << board[i])) {
        return 0;
      }
      check[10] |= (1 << board[i]);
    } else if (i % 9 < 6) {
      if (check[11] & (1 << board[i])) {
        return 0;
      }
      check[11] |= (1 << board[i]);
    } else {
      if (check[12] & (1 << board[i])) {
        return 0;
      }
      check[12] |= (1 << board[i]);
    }
  }
}

0

这是我刚刚为此所做的:

boolean checkers=true;
String checking="";
    if(a.length/3==1){}
    else{
       for(int l=1; l<a.length/3; l++){
            for(int n=0;n<3*l;n++){
                for(int lm=1; lm<a[n].length/3; lm++){
                    for(int m=0;m<3*l;m++){
                    System.out.print("    "+a[n][m]);
                    if(a[n][m]<=0){
                    System.out.print("        (Values must be positive!)        ");
                    }
                    if(n==0){
                        if(m!=0){
                        checking+=", "+a[n][m];
                    }
                    else{
                        checking+=a[n][m];
                    }
                }
                else{
                    checking+=", "+a[n][m];
                }
            }
                    }
            System.out.print("        "+checking);
            System.out.println();
                }
       }
            for (int i=1;i<=a.length*a[1].length;i++){
        if(checking.contains(Integer.toString(i))){

        }
        else{
            checkers=false;
        }
            }
        }
    checkers=checkCol(a);
    if(checking.contains("-")&&!checking.contains("--")){
        checkers=false;
    }
    System.out.println();
    if(checkers==true){
        System.out.println("This is correct! YAY!");
    }
    else{
        System.out.println("Sorry, it's not right. :-(");
    }
}
private static boolean checkCol(int[][]a){
    boolean checkers=true;
    int[][]col=new int[][]{{0,0,0},{0,0,0},{0,0,0}};
    for(int i=0; i<a.length; i++){
        for(int j=0; j<a[i].length; j++){
            if(a[i][j]>9||a[i][j]<1){
                checkers=false;
                break;
            }
            else{
                col[a[i].length-j][i]=a[i][j];
            }
        }
    }
    String alia="";
    for(int i=0; i<col.length; i++){
        for(int j=1; j<=col[i].length; j++){
            alia=a[i].toString();
            if(alia.contains(""+j)){
                alia=col[i].toString();
                if(alia.contains(""+j)){}
                else{
                    checkers=false;
                }   
            }
            else{
                checkers=false;
            }
        }
    }
    return checkers;
}

有一个 bug,但我忘记了。 :-( - user2425429

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接