通过回溯解决数独问题(java) publicstaticint[]solve(int[]input){ 对于(int i=0;i
我以前实现过一次数独解算器。它比你现在的要复杂一些,但一眨眼就解决了游戏。:) 你试图做的是用“暴力”和(尾巴)解数独递归。这意味着您正试图通过迭代所有981可能的组合来求解电路板。9到81的幂是…这是一个很大的数字。因此,您的方法将花费永恒的时间,但您将很快从尾部递归中耗尽堆栈空间 当我实现Sudoko时,它更直接。它保留了一个9x9“items”数组,其中每个items都是正方形中的值,还有一个9个布尔值的数组,表示候选对象(true==可行,false==消除)。然后它只做了一个非递归的求解电路板的循环通过回溯解决数独问题(java) publicstaticint[]solve(int[]input){ 对于(int i=0;i,java,recursion,backtracking,Java,Recursion,Backtracking,我以前实现过一次数独解算器。它比你现在的要复杂一些,但一眨眼就解决了游戏。:) 你试图做的是用“暴力”和(尾巴)解数独递归。这意味着您正试图通过迭代所有981可能的组合来求解电路板。9到81的幂是…这是一个很大的数字。因此,您的方法将花费永恒的时间,但您将很快从尾部递归中耗尽堆栈空间 当我实现Sudoko时,它更直接。它保留了一个9x9“items”数组,其中每个items都是正方形中的值,还有一个9个布尔值的数组,表示候选对象(true==可行,false==消除)。然后它只做了一个非递归的求
主循环将从查找只剩下1个候选方的简单过程开始。然后下一步将根据已分配的值进行简单的候选方消除。然后它将进入更复杂的消除技术,如。最终
validNumber()
方法将不会返回任何数字,因为没有剩余的可能性,这意味着前面的一个选择是错误的。只要想象一下,该算法是从空网格开始的(显然,这个谜题是可解的1)
解决方案是保留可能的选择树,如果某些选择不正确,则只需将它们从树中删除,然后使用下一个可用的选择(或者,如果此分支中没有选择,请后退到树的更高级别)。此方法应能找到解决方案(如果有的话)。(实际上,这就是我不久前实现数独解算器的方式。)
1我想有3种不同的数独游戏:
在“真”数独游戏中,结果是“真”根据定义的解决方案。对于模糊数独,结果可能会因算法而异。空网格是模糊数独的最终示例。您的算法实际上不会回溯。如果可以,它会向前移动,但当它意识到自己被困在角落时,它不会向后移动。这是因为它永远不会回溯在堆栈中重新设置任何知识,它永远不会重置方块。除非你运气好,否则你的代码将使游戏板进入转弯状态,然后打印出该转弯状态。要回溯,你需要将你设置的最后一个方块(使你转弯的方块)重置为零,这样你的算法就会知道继续尝试其他事情 为了理解回溯,我强烈推荐一本史蒂文·斯基纳的《算法设计手册》。我在准备SWE采访时读过这本书,它确实提高了我对回溯、复杂性和图形搜索的知识。这本书的后半部分是75个经典算法问题的目录,数独是其中之一m!他有一个有趣的优化分析,你可以对搜索树进行修剪,并解决非常困难的难题。下面是我很久以前在阅读本章后编写的一些代码(按照我目前的标准,质量可能不太高,但它是有效的).我只是很快地读了一遍,并在
solve
方法中添加了solveSmart
布尔值,它允许您打开或关闭其中一个优化,这在解决“硬”类数独板(一开始只填充了17个方块)时节省了大量时间
公共级数独{
静态类RowCol{
int行;
int col;
RowCol(整数r,整数c){
row=r;
col=c;
}
}
静态int numSquaresFilled;
静态整数[][]板=新整数[9][9];
静态无效打印板(){
对于(int i=0;i<9;i++){
对于(int j=0;j<9;j++){
系统输出打印(“+(板[i][j]==0?”:板[i][j])+”;
如果(j%3==2&&j<8)
系统输出打印(“|”);
}
System.out.println();
如果(i%3==2&&i<8)
System.out.println(“-----------|-----------------|-----------------”;
}
System.out.println();
}
静态布尔值isEntireBoardValid(){
对于(int i=0;i<9;i++){
对于(int j=0;j<9;j++){
如果(!isBoardValid(i,j)){
返回false;
}
}
}
返回true;
}
静态布尔值isRowValid(int行){
int[]计数=新的int[9];
for(int col=0;col<9;col++){
int n=线路板[行][col]-1;
如果(n==-1)
继续;
计数[n]++;
如果(计数[n]>1)
返回false;
}
返回true;
}
静态布尔值isColValid(整数列){
int[]计数=新的int[9];
对于(int行=0;行<9;行++){
int n=线路板[行][col]-1;
如果(n==-1)
继续;
计数[n]++;
如果(计数[n]>1)
返回false;
}
返回true;
}
静态布尔值isSquareValid(int行,int列){
int r=(第3行)*3;
int c=(col/3)*3;
int[]计数=新的int[9];
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
int n=电路板[r+i][c+j]-1;
如果(n==-1)
继续;
计数[n]++;
public static int[][] solve(int[][] input){
for (int i = 0; i < 9*9; i++){
if(input[i / 9][i % 9] != 0){
continue;
}
for (int j = 1; j <= 9; j++){
if(validNumber(input, i / 9, i % 9, j)){
input[i / 9][i % 9] = j;
solve(input);
}
}
}
return input;
}
public class Sudoku {
static class RowCol {
int row;
int col;
RowCol(int r, int c) {
row = r;
col = c;
}
}
static int numSquaresFilled;
static int[][] board = new int[9][9];
static void printBoard() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(" " + (board[i][j] == 0 ? " " : board[i][j]) + " ");
if (j % 3 == 2 && j < 8)
System.out.print("|");
}
System.out.println();
if (i % 3 == 2 && i < 8)
System.out.println("---------|---------|---------");
}
System.out.println();
}
static boolean isEntireBoardValid() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!isBoardValid(i, j)) {
return false;
}
}
}
return true;
}
static boolean isRowValid(int row) {
int[] count = new int[9];
for (int col = 0; col < 9; col++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isColValid(int col) {
int[] count = new int[9];
for (int row = 0; row < 9; row++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isSquareValid(int row, int col) {
int r = (row / 3) * 3;
int c = (col / 3) * 3;
int[] count = new int[9];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int n = board[r + i][c + j] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
}
return true;
}
static boolean isBoardValid(int row, int col) {
return (isRowValid(row) && isColValid(col) && isSquareValid(row, col));
}
static RowCol getOpenSpaceFirstFound() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
return new RowCol(i, j);
}
}
}
return new RowCol(0, 0);
}
static RowCol getOpenSpaceMostConstrained() {
int r = 0, c = 0, max = 0;
int[] rowCounts = new int[9];
int[] colCounts = new int[9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != 0)
rowCounts[i]++;
if (board[j][i] != 0)
colCounts[i]++;
}
}
int[][] squareCounts = new int[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int count = 0;
for (int m = 0; m < 3; m++) {
for (int n = 0; n < 3; n++) {
if (board[(i * 3) + m][(j * 3) + n] != 0)
count++;
}
}
squareCounts[i][j] = count;
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
if (rowCounts[i] > max) {
max = rowCounts[i];
r = i;
c = j;
}
if (colCounts[j] > max) {
max = rowCounts[j];
r = i;
c = j;
}
}
}
}
return new RowCol(r, c);
}
static boolean solve() {
if (81 == numSquaresFilled) {
return true;
}
boolean solveSmart = true;
RowCol rc = solveSmart ? getOpenSpaceMostConstrained() : getOpenSpaceFirstFound();
int r = rc.row;
int c = rc.col;
for (int i = 1; i <= 9; i++) {
numSquaresFilled++;
board[r][c] = i;
if (isBoardValid(r, c)) {
if (solve()) {
return true;
}
}
board[r][c] = 0;
numSquaresFilled--;
}
return false;
}
public static void main(String[] args) {
// initialize board to a HARD puzzle
board[0][7] = 1;
board[0][8] = 2;
board[1][4] = 3;
board[1][5] = 5;
board[2][3] = 6;
board[2][7] = 7;
board[3][0] = 7;
board[3][6] = 3;
board[4][3] = 4;
board[4][6] = 8;
board[5][0] = 1;
board[6][3] = 1;
board[6][4] = 2;
board[7][1] = 8;
board[7][7] = 4;
board[8][1] = 5;
board[8][6] = 6;
numSquaresFilled = 17;
printBoard();
long start = System.currentTimeMillis();
solve();
long end = System.currentTimeMillis();
System.out.println("Solving took " + (end - start) + "ms.\n");
printBoard();
}
}