遞迴暴力破解法解數獨問題
阿新 • • 發佈:2019-01-01
C語言原始碼如下,在Linux平臺下用GCC編譯通過並執行。附資料檔案sudoku.dat及計算結果。
8--------
--36-----
-7--9-2--
-5---7---
----457--
---1---3-
--1----68
--85---1-
-9----4--
812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452
編譯及執行方法:
gcc sudoku.c -o sudoku
./sudoku < sudoku.dat
#include <stdio.h> #include <string.h> #define ROWS 9 #define COLS 9 #define BLKS 9 #define NAN '-' typedef enum { false = 0, true = !false } bool; struct step { char num[ROWS][COLS]; int cell[ROWS][COLS]; }; static int ctz(int x) { return __builtin_ctz(x); } static int rowcol2blk(int row, int col) { return row / 3 * 3 + col / 3; } static int blk2row(int blk) { return blk / 3 * 3; } static int blk2col(int blk) { return blk % 3 * 3; } bool setnum(struct step *curr, int row, int col, int num); void init(struct step *curr) { int row, col; for (row = 0; row < ROWS; ++row) { for (col = 0; col < COLS; ++col) { curr->cell[row][col] = 0x3FE; curr->num[row][col] = NAN; } } } bool exclude(struct step *curr, int row, int col, int num) { int x = curr->cell[row][col] & ~(1 << num); if (0 == x) return false; curr->cell[row][col] = x; if (NAN != curr->num[row][col] || 0 != (x & (x - 1))) return true; return setnum(curr, row, col, ctz(x)); } bool setnum(struct step *curr, int row, int col, int num) { int mask = 1 << num; int blk = rowcol2blk(row, col); int r, c, r0, c0; if (0 == (curr->cell[row][col] & mask)) return false; curr->num[row][col] = '0' + num; curr->cell[row][col] = mask; for (r = 0; r < ROWS; ++r) { if (r == row) continue; if (!exclude(curr, r, col, num)) return false; } for (c = 0; c < COLS; ++col) { if (c == col) continue; if (!exclude(curr, row, c, num)) return false; } r0 = blk2row(blk); c0 = blk2col(blk); for (r = r0; r < r0 + 3; ++r) { for (c= c0; c < c0 + 3; ++c) { if (r == row && c == col) continue; if (!exclude(curr, r, c, num)) return false; } } return true; } bool try(struct step *curr) { struct step next; int row, col, num; int cell; for (row = 0; row < ROWS; ++row) { for (col = 0; col < COLS; ++col) { if (NAN == curr->num[row][col]) goto outer; } } outer: if (row > ROWS) return true; cell = curr->cell[row][col]; while (0 != cell) { memcpy(&next, curr, sizeof next); num = ctz(cell); if (setnum(&next, row, col, num) && try(&next)) { memcpy(curr, &next, sizeof *curr); break; } cell &= ~(1 << num); } return (0 != cell); } int main() { struct step step; int row, col, num; init(&step); for (row = 0; row < ROWS; ++row) { for (col = 0; col < COLS; ++col) { if (NAN == (num = getchar())) continue; if (!setnum(&step, row, col, num - '0')) { puts("no answer\n"); return 1; } } num = getchar(); /* new line */ } if (!try(&step)) { puts("no answer\n"); return 1; } for (row = 0; row < ROWS; ++row) { for (col = 0; col < COLS; ++col) { putchar(step.num[row][col]; } putchar('\n'); } return 0; }