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...else
和displayDigits(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
中的代码。 grid
和 currentCellDigit
之间有几个冗余分配。 i
和 j
之一是多余的,它们具有相同的值。
使用调试器了解您的代码在做什么。
更好的缩进将使您的代码更具可读性。
【讨论】:
【参考方案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问题中的蛮力数独求解器算法的主要内容,如果未能解决你的问题,请参考以下文章