Sudoku Solver
Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by thecharacter '.'.
You may assume that there will be only one unique solution.
思路:本题是典型的回溯法题型,类似的题目还有迷宫求解,8皇后问题。回溯法解题的一般思路是深度优先算法。
若采用递归求解,轮训所有状态(分支),找到一个合法状态,就继续递归深入,如果不合法,则轮训下一个状态(下一个分支)。如果所有状态都轮训完还没有找到合法状态,则恢复为原始状态后,直接返回(剪枝),回溯到上一个状态。如不采用递归,则使用栈,模拟递归。
本题在解决数独问题时,首先在第一个”.”处,从1到9,分别判断那个值是合法的,找到一个合法值,则寻找第二个”.”,依次深入。如果某个节点,从1到9都不合法,则恢复该节点的状态(”.”),然后回溯到上一个”.”处,继续轮训下一个状态。
剩下的问题就是,如何判断某个值是否合法,很简单,从该值所处的行、列和区域内,查看是否有重复的值即可。代码如下,包含了递归和非递归的算法:
<pre name="code" class="cpp">typedef struct { int i, j; int value; }node; typedef struct { node **sets; int len; int top; }Stack; int push(Stack *s, node *key) { if(s->top >= s->len) return -1; s->sets[s->top ++] = key; return 0; } node *pop(Stack *s) { if(s->top == 0) return NULL; return s->sets[-- s->top]; } Stack *initstack(int stlen) { Stack *st = calloc(1, sizeof(Stack)); st->sets = calloc(stlen, sizeof(node *)); st->len = stlen; st->top = 0; return st; } void freestack(Stack *s) { node *top = NULL; while((top = pop(s)) != NULL) { free(top); } free(s); } int isSafe(char** board, int boardRowSize, int boardColSize, node *top) { int i, j, value; int tmp = -1; i = top->i; j = top->j; value = top->value; int m, n; for(m = 0; m < boardColSize; m++) { if(m == j) continue; tmp = board[i][m] - '0'; if(tmp == value) return 0; } for(m = 0; m < boardRowSize; m++) { if(m == i) continue; tmp = board[m][j] - '0'; if(tmp == value) return 0; } int lineend = i/3 * 3 + 3; int colend = j/3 * 3 + 3; for(m = i/3 * 3; m < lineend; m++) { for(n = j/3 * 3; n < colend; n++) { if(m == i && n == j) continue; tmp = board[m][n] - '0'; if(tmp == value) return 0; } } return 1; } void solveSudoku_loop(char **board, int boardRowSize, int boardColSize) { int i, j, tmp; Stack *s = initstack(81); node *top = NULL; for(i = 0; i < boardRowSize; i++) { for(j = 0; j < boardColSize; j++) { if(board[i][j] == '.') { node *newnode = calloc(1, sizeof(node)); newnode->i = i; newnode->j = j; newnode->value = 1; board[i][j] = newnode->value + '0'; push(s, newnode); top = newnode; while(isSafe(board, boardRowSize, boardColSize, top) == 0) { top = pop(s); while(top != NULL && top->value == 9) { board[top->i][top->j] = '.'; top = pop(s); } if(top == NULL) { printf("no solution\n"); freestack(s); return; } top->value += 1; board[top->i][top->j] = top->value + '0'; push(s, top); } i = top->i; j = top->j; } } } freestack(s); } int findemptyblank(char **board, int boardRowSize, int boardColSize, int *i, int *j) { int m, n; for(m = 0; m < boardRowSize; m++) { for(n = 0; n < boardColSize; n++) { if(board[m][n] == '.') { *i = m; *j = n; return 1; } } } return 0; } int solveSudoku_recurse(char **board, int boardRowSize, int boardColSize) { int i, j, k; if(findemptyblank(board, boardRowSize, boardColSize, &i, &j) == 0) { return 1; } node newnode; newnode.i = i; newnode.j = j; for(k = 1; k <= 9; k++) { newnode.value = k; if(isSafe(board, boardRowSize, boardColSize, &newnode)) { board[i][j] = k + '0'; if(solveSudoku_recurse(board, boardRowSize, boardColSize)) { return 1; } } } board[i][j] = '.'; return 0; } int isValidSudoku(char** board, int boardRowSize, int boardColSize) { int hashline[10][10]; int hashcol[10][10]; int hashzone[10][10]; int i, j; int tmp = -1; int zone = -1; for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { hashline[i][j] = hashcol[i][j] = hashzone[i][j] = 0; } } for(i = 0; i < boardRowSize; i++) { for(j = 0; j < boardColSize; j++) { tmp = board[i][j]; if(tmp == '.') continue; else tmp = tmp - '0'; zone = (i / 3) * 3 + j / 3; if(hashline[tmp][i]) return 0; if(hashcol[tmp][j]) return 0; if(hashzone[tmp][zone]) return 0; hashline[tmp][i] = hashcol[tmp][j] = hashzone[tmp][zone] = 1; } } return 1; } void printsudoku(char** board, int boardRowSize, int boardColSize) { int i, j; printf("\n"); for(i = 0; i < boardRowSize; i++) { if(i % 3 == 0) { printf("--------------------\n"); } for(j = 0; j < boardColSize; j++) { if(j % 3 == 0) { printf("|"); } printf("%c ", board[i][j]); } printf("\n"); } } void solveSudoku(char **board, int boardRowSize, int boardColSize) { solveSudoku_loop(board, boardRowSize, boardColSize); //solveSudoku_recurse(board, boardRowSize, boardColSize); }
呵呵