Java问题中的蛮力数独求解器算法

Posted

技术标签:

【中文标题】Java问题中的蛮力数独求解器算法【英文标题】:Brute force sudoku solver algorithm in Java problem 【发布时间】:2011-05-01 16:12:17 【问题描述】:

除了求解方法之外,算法中的一切似乎都运行良好。当它使用可解数独板执行程序时,它说它无法解出。我已经尝试了解决方法中我能想到的一切。我尝试过调试,但在测试第一行后它失败了。有什么建议?以下是目前的完整代码:

    public class SudokuSolver 

 public static void initializeGrid(int[][] grid, int[][] puzzle) 

  for (int r = 0; r < puzzle.length; r++) 
  for (int c = 0; c < puzzle[0].length; c++) 
  grid [r][c] = puzzle [r][c];
   
   
 

 public static void displayGrid(int[][] grid) 

  for (int r = 0; r < grid.length; r++) 
   if (r % 3 == 0) 
   System.out.println("+---+---+---+");
   
   for (int c = 0; c < grid[r].length; c++) 
if (c % 3 == 0) 
 System.out.print("|");

displayDigits(r, c, grid);

System.out.print("|"); System.out.println(); System.out.println("+---+---+---+");

if (grid[r][c] == 0) System.out.print(' '); else System.out.print(grid[r][c]); public static int getEmptyCells(int[][] grid, int[][] emptyCells) int i = 0; int numEmptyCells = 0; for (int r = 0; r < grid.length; r++) for (int c = 0; c < grid[r].length; c++) if (grid[r][c] == 0) emptyCells[i][0] = r; emptyCells[i][1] = c; numEmptyCells++; i++; return numEmptyCells;

private static boolean hasNoDuplicates(int[] digitsList) for (int j = 0; j < digitsList.length; j++) for (int k = j + 1; k < digitsList.length; k++) if (digitsList[j] == digitsList[k] && digitsList[j] != 0) return false; return true;

private static boolean checkCurrentRow(int[][] grid, int currentRow) int[] digitsList = new int[grid.length]; for (int c = 0; c < digitsList.length; c++) digitsList[c] = grid[currentRow][c]; if (hasNoDuplicates(digitsList)) return true; return false;

private static boolean checkCurrentCol(int[][] grid, int currentCol) int[] digitsList = new int[grid.length]; for (int i = 0; i < digitsList.length; i++) digitsList[i] = grid[i][currentCol]; if (hasNoDuplicates(digitsList)) return true; return false;

private static boolean checkCurrentRegion(int[][] grid, int currentRow, int currentCol) int[] digitsList = new int[grid.length]; currentRow = (currentRow / 3) * 3; currentCol = (currentCol / 3) * 3; int i = 0; for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) digitsList[i] = grid[currentRow + r][currentCol + c]; i++; if (hasNoDuplicates(digitsList)) return true; return false;

public static boolean isConsistent(int[][] grid, int currentRow, int currentCol) if (checkCurrentRow(grid, currentRow) && checkCurrentCol(grid, currentCol) && checkCurrentRegion(grid, currentRow, currentCol)) return true; return false;

public static boolean solvePuzzle(int[][] grid, int[][] emptyCells, int numEmptyCells) int i = 0; int j = 0; int currentCellDigit = grid[emptyCells[i][0]][emptyCells[i][1]]; while (j < numEmptyCells) if (currentCellDigit != 9) currentCellDigit++; grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellDigit; if (isConsistent(grid, emptyCells[i][0], emptyCells[i][1])) grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellDigit; i++; j++; else grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellDigit - 1; else currentCellDigit = 0; currentCellDigit = grid[emptyCells[i][0]][emptyCells[i][1]]; i--; j--; if (j < 0) return false;

return true;

public static void main(String[] args)

final int SIZE = 9; int[][] puzzle = 0,2,9,0,0,3,0,0,5, 5,0,7,0,0,0,0,9,0, 6,0,0,0,0,9,4,2,0, 3,0,2,0,0,4,0,0,0, 0,0,5,0,3,0,7,0,0, 0,0,0,5,0,0,6,0,2, 0,9,8,4,0,0,0,0,3, 0,3,0,0,0,0,1,0,6, 2,0,0,3,0,0,9,4,0 ;

int[][] grid = new int[SIZE][SIZE]; int[][] emptyCellsList = new int[SIZE*SIZE][2]; int numEmptyCells = 0;

initializeGrid(grid, puzzle); numEmptyCells = getEmptyCells(grid, emptyCellsList); System.out.println("The puzzle:"); displayGrid(puzzle); if (solvePuzzle(grid, emptyCellsList, numEmptyCells)) System.out.println("has been solved:"); displayGrid(grid); else System.out.println("cannot be solved!");

【问题讨论】:

我无法立即看到任何内容,但这似乎是一种过于复杂的操作方式,您是否有理由强制使用它? 这是学校作业。我知道它过于复杂,但这是我们必须这样做的方式。 这不会编译,到目前为止还没有。 @SeanPatrickFloyd 我发现的主要问题是一个额外的右括号。还有一个不合适的if...elsedisplayDigits(int, int, int[][]) 丢失了。 【参考方案1】:

您的 initializeGrid 错误。恕我直言,应该是:

for (int c = 0; c < puzzle[r].length; c++)

而不是

for (int c = 0; c < puzzle[0].length; c++)

编辑:我在下面的回答

它已正确缩进(第 1 课)并相应地排列了花括号(第 2 课)。学习逐行理解你正在尝试做什么,当你被困在特定的行或方法调用上时,寻求帮助(第 3 课)。下面的代码将编译但不会(还)解决这个难题。为我阅读并替换 solvePuzzle 中的 cmets(第 4 课)。做一些思考和分析,因为这是你的作业;)祝你好运!

public class SudokuSolver 
  public static void initializeGrid(int[][] grid, int[][] puzzle) 
   for (int r = 0; r < puzzle.length; r++) 
     for (int c = 0; c < puzzle[0].length; c++) 
       grid [r][c] = puzzle [r][c];
     
    
  
  
  public static void displayDigits(int r, int c, int[][] grid) 
    if (grid[r][c] == 0) 
      System.out.print('0');
     else 
      System.out.print(grid[r][c]);
    
  

  public static void displayGrid(int[][] grid) 
    for (int r = 0; r < grid.length; r++) 
      if (r % 3 == 0) 
        System.out.println("+---+---+---+");
      
      for (int c = 0; c < grid[r].length; c++) 
        if (c % 3 == 0) 
          System.out.print("|");
        
      displayDigits(r, c, grid);
      
      System.out.print("|");
      System.out.println();
    
    System.out.println("+---+---+---+");
  
 
  public static int getEmptyCells(int[][] grid, int[][] emptyCells) 
    int i = 0;
    int numEmptyCells = 0;
    for (int r = 0; r < grid.length; r++) 
       for (int c = 0; c < grid[r].length; c++) 
         if (grid[r][c] == 0) 
           emptyCells[i][0] = r;
           emptyCells[i][1] = c;
           numEmptyCells++;
           i++;
         
       
    
    return numEmptyCells;
  
  
  private static boolean hasNoDuplicates(int[] digitsList) 
    for (int j = 0; j < digitsList.length; j++) 
      for (int k = j + 1; k < digitsList.length; k++) 
        if (digitsList[j] == digitsList[k] && digitsList[j] != 0)
          return false;
      
    
    return true;
  

  private static boolean checkCurrentRow(int[][] grid, int currentRow) 
    int[] digitsList = new int[grid.length];
    for (int c = 0; c < digitsList.length; c++) 
      digitsList[c] = grid[currentRow][c];
    
    if (hasNoDuplicates(digitsList)) 
      return true;
    
    return false;
  

  private static boolean checkCurrentCol(int[][] grid, int currentCol) 
    int[] digitsList = new int[grid.length];
    for (int i = 0; i < digitsList.length;  i++) 
      digitsList[i] = grid[i][currentCol];
    
    if (hasNoDuplicates(digitsList)) 
      return true;
    
    return false;
  

  private static boolean checkCurrentRegion(int[][] grid, int currentRow,
       int currentCol) 
    int[] digitsList = new int[grid.length];
    currentRow = (currentRow / 3) * 3;
    currentCol = (currentCol / 3) * 3;
    int i = 0;
    for (int r = 0; r < 3; r++) 
      for (int c = 0; c < 3; c++) 
        digitsList[i] = grid[currentRow + r][currentCol + c];
        i++;
      
    
    if (hasNoDuplicates(digitsList)) 
      return true;
    
    return false;
  

  public static boolean isConsistent(int[][] grid, int currentRow,
       int currentCol) 
    boolean checkRow = checkCurrentRow(grid, currentRow);
    boolean checkCol = checkCurrentCol(grid, currentCol);
    boolean checkReg = checkCurrentRegion(grid, currentRow, currentCol);
    System.out.println("r: " + checkRow + " c: " + checkCol + " r: " + checkReg);
    if (checkRow && checkCol && checkReg) 
      return true;
    
    return false;
  

  public static boolean solvePuzzle(int[][] grid, int[][] emptyCells,
      int numEmptyCells) 
    int i = 0;
    int currentCellDigit = 0;
    while (i < numEmptyCells) 
      if (currentCellDigit != 9) 
        // increment cell value
        currentCellDigit++;
        // assign to current cell the current cell value
        //<var> = currentCellDigit;
        System.out.println("Solving---------------------- :" +
            currentCellDigit + " R: " +
            emptyCells[i][0] + " C: " + emptyCells[i][1]);
        // check if value is valid
        if (isConsistent(grid, emptyCells[i][0], emptyCells[i][1])) 
          // reset after setting
          i++;
          currentCellDigit = 0;
         else 
          // reset cell to zero instead of decrementing it since we're backtracking!
          //grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellDigit - 1;
          //<var> = 0;
        
       else 
        // reset current cell to 0
        //<var> = 0;
        // go to previous cell
        i--;
        // exit if theres no cell to backtrack to
        if (i < 0) 
          return false;
        
        // set previous' cell value as current cell value
        //<var> = grid[emptyCells[i][0]][emptyCells[i][1]];
      
    
    return true;
  
  
  public static void main(String[] args) 
    final int SIZE = 9;
    int[][] puzzle  =  0,2,9,0,0,3,0,0,5,
                        5,0,7,0,0,0,0,9,0,
                        6,0,0,0,0,9,4,2,0,
                        3,0,2,0,0,4,0,0,0,
                        0,0,5,0,3,0,7,0,0,
                        0,0,0,5,0,0,6,0,2,
                        0,9,8,4,0,0,0,0,3,
                        0,3,0,0,0,0,1,0,6,
                        2,0,0,3,0,0,9,4,0
                    ;

    int[][] grid = new int[SIZE][SIZE];
    int[][] emptyCellsList = new int[SIZE*SIZE][2];
    int numEmptyCells = 0;

    initializeGrid(grid, puzzle);
    numEmptyCells = getEmptyCells(grid, emptyCellsList);
    System.out.println("The puzzle:");  
    displayGrid(puzzle);
    if (solvePuzzle(grid, emptyCellsList, numEmptyCells)) 
      System.out.println("has been solved:");
      displayGrid(grid);
     else 
      System.out.println("cannot be solved!");
    
  

附:如果您用正确的代码替换了上面的 cmets,这将执行回溯。

【讨论】:

因为我只使用 9x9 板,与 '0' 相比,'r' 对初始化没有影响。该算法的问题似乎发生在 SOLVE 方法中。 非常感谢您的帮助。逐行浏览确实很有帮助。【参考方案2】:

仔细考虑solvePuzzle 中的代码。 gridcurrentCellDigit 之间有几个冗余分配。 ij 之一是多余的,它们具有相同的值。

使用调试器了解您的代码在做什么。

更好的缩进将使您的代码更具可读性。

【讨论】:

【参考方案3】:
public static boolean solvePuzzle(int[][] grid, int[][] emptyCells,
        int numEmptyCells) 
    int i = 0;
    int currentCellNum = 0;
    while (i < numEmptyCells) 
        currentCellNum = grid[emptyCells[i][0]][emptyCells[i][1]];
        if (currentCellNum != 9) 
            currentCellNum++;
            grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellNum;
            if (isConsistent(grid, emptyCells[i][0], emptyCells[i][1])) 
                i++;
             
         else 
            currentCellNum = 0;
            grid[emptyCells[i][0]][emptyCells[i][1]] = currentCellNum;
            i--;
            if (i < 0) 
                return false;
            

        
    
    return true;

【讨论】:

以上是关于Java问题中的蛮力数独求解器算法的主要内容,如果未能解决你的问题,请参考以下文章

如何测量用 Java 编写的代码的速度? (人工智能算法)

如何为回溯算法获得更严格的界限?

优化回溯算法求解数独

Java indexOf(蛮力方法)对我或其他一些子字符串算法更实用吗?

为啥这个“数独求解器”算法不起作用

数独求解器回溯算法不起作用