// 题目链接http://poj.org/problem?id=3074 // 精确覆盖问题求解转载:https://www.cnblogs.com/grenet/p/3145800.html // 把数独问题转换为精确覆盖问题转载:https://www.cnblogs.com/grenet/p/3163550.html 1 #includecs
// 题目链接 http://poj.org/problem?id=3074
// 精确覆盖问题求解转载:https://www.cnblogs.com/grenet/p/3145800.html
// 把数独问题转换为精确覆盖问题转载:https://www.cnblogs.com/grenet/p/3163550.html
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 6 //const int INF = 1 << 30; 7 const int maxn = 729; 8 const int maxnode = 2916; 9 const int maxnr = 729; 10 11 //行编号从1开始,列编号为1~n,结点0是表头结点;结点1~n是各列顶部的虚拟结点 12 struct DLX { 13 int n, sz;//列数, 结点总数 14 int S[maxn];//各列节点数 15 16 int row[maxnode], col[maxnode];//各结点行列编号 17 int L[maxnode], R[maxnode], U[maxnode], D[maxnode];//十字链表 18 19 int ansd, ans[maxnr];//解 20 21 void init(int n) {//n是列数 22 this->n = n; 23 24 //虚拟结点 25 for(int i = 0; i <= n; ++i) { 26 U[i] = i; 27 D[i] = i; 28 L[i] = i-1; 29 R[i] = i+1; 30 } 31 R[n] = 0; L[0] = n; 32 33 sz = n + 1; 34 memset(S, 0, sizeof(S)); 35 } 36 37 void addRow(int r, vector<int> columns) { 38 int first = sz; 39 for(int i = 0; i != columns.size(); ++i) { 40 int c = columns[i]; 41 L[sz] = sz-1; R[sz] = sz+1; D[sz] = c; U[sz] = U[c]; 42 D[U[c]] = sz; U[c] = sz; 43 row[sz] = r; col[sz] = c; 44 S[c]++; sz++; 45 } 46 R[sz-1] = first; L[first] = sz-1; 47 } 48 // 顺着链表A, 遍历除s外的其它元素 49 #define FOR(i, A, s) for(int i = A[s]; i != s; i = A[i]) 50 51 void remove(int c) { 52 L[R[c]] = L[c]; 53 R[L[c]] = R[c]; 54 FOR(i, D, c) 55 FOR(j, R, i) { 56 U[D[j]] = U[j]; 57 D[U[j]] = D[j]; 58 --S[col[j]]; 59 } 60 } 61 62 void restore(int c) { 63 FOR(i, U, c) 64 FOR(j, L, i) { 65 ++S[col[j]]; 66 U[D[j]] = j; 67 D[U[j]] = j; 68 } 69 L[R[c]] = c; 70 R[L[c]] = c; 71 } 72 73 // d为递归深度 74 bool dfs(int d) { 75 if(R[0] == 0) { // 找到解 76 ansd = d; // 记录解的长度 77 return true; 78 } 79 80 // 找s最小的列c 81 int c = R[0]; // 第一个未删除的列 82 FOR(i, R, 0) if(S[i] < S[c]) c = i; 83 84 remove(c); // 删除c列 85 FOR(i, D, c) { // 用结点i所在的行覆盖第c列 86 ans[d] = row[i]; 87 FOR(j, R, i) remove(col[j]);// 删除结点i所在行能覆盖的所有其它列 88 if(dfs(d+1)) return true; 89 FOR(j, L, i) restore(col[j]);// 恢复结点i所在行能覆盖的所有其它列 90 } 91 restore(c); // 恢复第c列 92 93 return false; 94 } 95 96 bool solve(vector<int>& v) { 97 v.clear(); 98 if(!dfs(0)) return false; 99 for(int i = 0; i != ansd; ++i) v.push_back(ans[i]); 100 return true; 101 } 102 }; 103 104 const int SLOT = 0; 105 const int ROW = 1; 106 const int COL = 2; 107 const int SUB = 3; 108 109 inline int encode(int a, int b, int c) { 110 return a*81 + b*9 + c + 1; 111 } 112 113 inline void decode(int code, int &a, int &b, int &c) { 114 code--; 115 c = code%9; code /= 9; 116 b = code%9; code /= 9; 117 a = code; 118 } 119 120 DLX solver; 121 122 int main() { 123 char str[81]; 124 char puzzle[9][9]; 125 while(scanf("%s", str) == 1 && strcmp(str, "end")) { 126 solver.init(324); 127 for(int i = 0; i != 9; ++i) { 128 for(int j = 0; j != 9; ++j) { 129 puzzle[i][j] = str[i*9 + j]; 130 } 131 } 132 for(int r = 0; r != 9; ++r) { 133 for(int c = 0; c != 9; ++c) { 134 for(int v = 0; v != 9; ++v) { 135 if(puzzle[r][c] == ‘.‘ || puzzle[r][c]-‘0‘ == v+1) { 136 vector<int> columns; 137 columns.push_back(encode(SLOT, r, c)); 138 columns.push_back(encode(ROW, r, v)); 139 columns.push_back(encode(COL, c, v)); 140 columns.push_back(encode(SUB, (r/3)*3 + c/3, v)); 141 solver.addRow(encode(r, c, v), columns); 142 } 143 } 144 } 145 } 146 vector<int> ans; 147 solver.solve(ans); 148 149 for(int i = 0; i != ans.size(); ++i) { 150 int r, c, v; 151 decode(ans[i], r, c, v); 152 puzzle[r][c] = ‘1‘+v; 153 } 154 for(int i = 0; i != 9; ++i) { 155 for(int j = 0; j != 9; ++j) { 156 printf("%c", puzzle[i][j]); 157 } 158 } 159 printf("\n"); 160 } 161 return 0; 162 }