dlx算法解數獨,有空會寫詳解,暫時就這樣了 node
Sudoku
Description git In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example, 算法
Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns. 數組 Input app The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word 「end」. ide Output spa For each test case, print a line representing the completed Sudoku puzzle. .net Sample Input code .2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534. ......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3. end Sample Output ip 527389416819426735436751829375692184194538267268174593643217958951843672782965341 416837529982465371735129468571298643293746185864351297647913852359682714128574936 Source |
[Submit] [Go Back] [Status] [Discuss]
/*============================================================================= # FileName: 3074.cpp # Desc: # Author: zhuting # Email: cnjs.zhuting@gmail.com # HomePage: my.oschina.net/locusxt # Version: 0.0.1 # CreatTime: 2014-01-16 21:44:18 # LastChange: 2014-01-16 21:44:18 # History: =============================================================================*/ /* * 數獨須要知足的四個條件: * 1.每一個格子都有數字 * 2.每一行要有1-9 * 3.每一列要有1-9 * 4.每一個3*3的塊要有1-9 * * 1-81列 表示某個格子有沒有填數字,填了則爲1 * 82-162列 表示某一行有沒有1-9 * 163-243列 表示某一列有沒有1-9 * 244-324列 表示某個塊有沒有1-9 * * 共9*9*9行 * 表示某一個格子填了某個數後的影響 */ #include <cstdio> #include <cstdlib> #include <string> #include <cstring> #include <algorithm> #define maxl 100 #define maxc 325 //最大列數,包含頭結點 #define maxr 730 //最大行數,包含待匹配行 #define maxn 240000 //最大總結點數 #define head 0 //head的編號爲0 #define GET_CEL(i, j, k) i*9+j #define GET_ROW(i, j, k) 80+i*9+k #define GET_COL(i, j, k) 161+j*9+k #define GET_BLO(i, j, k) 242+(3*(i/3)+j/3)*9+k #define GET_I(l) (l-1)/81 #define GET_J(l) (l-1)%81/9 #define GET_K(l) (l-1)%81%9+1 const int m = 729;//行數 const int n = 324;//列數 bool mymap[maxr][maxc]; int num[maxc] = {0}; //數組實現的dancing links int up[maxn] = {0}, down[maxn] = {0}, left[maxn] = {0}, right[maxn] = {0};//顧名思義是某個結點的上下左右結點的標號 int column[maxn] = {0}, row[maxn] = {0}, ans[maxn] = {0};//某個結點對應的行號,ans是取的行號的數組 char str[maxl]; /* * 每填一個數,假設填在數獨i行j列填的是k * 那麼會產生如下影響: * 9*j+i個cell被填上了數字 */ //生成初始的01串 void gen_zero_one() { int cur_line = 0; for (int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { for (int k = 1; k <= 9; ++k) { mymap[cur_line][GET_CEL(i, j, k)] = 1; mymap[cur_line][GET_ROW(i, j, k)] = 1; mymap[cur_line][GET_COL(i, j, k)] = 1; mymap[cur_line][GET_BLO(i, j, k)] = 1; ++cur_line; } } } return; } //生產初始的節點表 void gen_node() { int id = 1; int tmp = 0; int lineup[maxc] = {0}; for (int j = 0; j < n; ++j)//待匹配行 { lineup[j] = id; column[id] = j + 1; if (j != n - 1) { right[id] = id + 1; } left[id] = id - 1; ++id; } right[head] = 1; left[head] = id - 1; right[id - 1] = head; for (int i = 0; i < m; ++i) { int first_id = 0; int left_id = 0; for (int j = 0; j < n; ++j) { //scanf("%d", &tmp); tmp = mymap[i][j]; if (tmp) { row[id] = i + 1; column[id] = j + 1; if (first_id == 0) { first_id = id; left_id = id; } else { left[id] = left_id; right[left_id] = id; left_id = id; } int upid = lineup[j]; up[id] = upid; down[upid] = id; lineup[j] = id; ++id; } } if (first_id != 0) { left[first_id] = left_id; right[left_id] = first_id; } } for (int j = 0; j < n; ++j) { down[lineup[j]] = j + 1; up[j + 1] = lineup[j]; } //test(id); return; } void init()//初始化 { memset(up, 0, sizeof(up)); memset(down, 0, sizeof(down)); memset(left, 0, sizeof(left)); memset(right, 0, sizeof(right)); memset(column, 0, sizeof(column)); memset(row, 0, sizeof(row)); memset(ans, 0, sizeof(ans)); memset(mymap, 0, sizeof(mymap)); for (int i = 1; i <= n; ++i) num[i] = 9; return; } //這裏的remove其實並無真正刪除掉結點,能夠用resume恢復 void remove(int c)//去掉c號結點,以及在c所在列上有結點的行的結點 { left[right[c]] = left[c]; right[left[c]] = right[c]; for (int i = down[c]; i != c; i = down[i]) { for (int j = right[i]; j != i; j = right[j]) { up[down[j]] = up[j]; down[up[j]] = down[j]; --num[column[j]]; } } return; } void resume(int c)//remove的逆操做 { left[right[c]] = c; right[left[c]] = c; for (int i = up[c]; i != c; i = up[i]) { for (int j = right[i]; j != i; j = right[j]) { up[down[j]] = j; down[up[j]] = j; ++num[column[j]]; } } return; } void recover(int t) { for (int i = 0; i < t; ++i) { int tmp = ans[i]; int cur = GET_I(tmp) * 9 + GET_J(tmp); str[cur] = GET_K(tmp) + '0'; /* printf("%d:\n", tmp); printf("%d %d %d\n", GET_I(tmp), GET_J(tmp), GET_K(tmp)); */ } return; } //咱們的終極目標其實是把十字鏈表中全部的結點都刪掉,只留一個頭結點 bool dance(int k)//這裏的k其實是沒多大意義的 { //printf("dance: %d\n", k); int c = right[head];//c是頭結點的右邊一個結點 if (c == head)//只剩下十字鏈表的頭結點,則完成了目標 { recover(k); return true; } int min_n = num[c]; int min_cur = c; while(true) { c = right[c]; if (c == head) break; if(num[c] < min_n) { min_n = num[c]; min_cur = c; } } c = min_cur; remove(c); for (int i = down[c]; i != c; i = down[i])//這裏實際上是枚舉某一行對待匹配行的第c位進行匹配 { ans[k] = row[i]; for (int j = right[i]; j != i; j = right[j]) remove(column[j]);//remove待匹配行的column[j]結點 if (dance(k + 1)) return true; for (int j = left[i]; j != i; j = left[j]) resume(column[j]); } resume(c); return false; } void parse(char* a) { int tmp = 0; for(int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { if(a[i * 9 + j] != '.') { tmp = a[i * 9 + j] - '0'; remove(GET_CEL(i, j, tmp) + 1); remove(GET_ROW(i, j, tmp) + 1); remove(GET_COL(i, j, tmp) + 1); remove(GET_BLO(i, j, tmp) + 1); } } } return; } int main() { while (true) { scanf("%s", str); if (str[0] == 'e') { break; } init(); gen_zero_one(); gen_node(); parse(str); int is_possible = dance(0); if (is_possible) { printf("%s\n", str); } else printf("error\n"); } return 0; }