dance link X算法是用来解决精确覆盖问题,例如在一个01矩阵中,找n行,能使得每一列都只有一个1,其余全是0. 而怎么将求解数独转化为DLX能解决的问题呢? 假设是一个9*9的数独,每一行,每一列,每个宫都要有1~9这9个数,每一个格子都有9个状态,所以一共有9*9*9的状态,所以DLX要建729行,然后用9*9来表示每个格子都有数字了,每行每列每宫都要9*9来表示当前行/列/宫有数字k了.一共4*9*9列.
直接上题目吧POJ3074
sourse code:cpp
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int N = 9; //3*3 数独 5 const int MaxN = N * N * N + 10; 6 const int MaxM = N * N * 4 + 10; 7 const int maxnode = MaxN * 4 + MaxM + 10; 8 char g[MaxN]; 9 struct DLX { 10 int n, m, size; 11 int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode]; 12 int H[MaxN], S[MaxM];//S维护每一列有多少个点,H维护每一行的头 13 int ansd, ans[MaxN]; 14 void init(int _n, int _m) {//m维护每一列,n维护每一行 15 n = _n; 16 m = _m; 17 for (int i = 0; i <= m; i++) { 18 S[i] = 0; 19 U[i] = D[i] = i; 20 L[i] = i - 1; 21 R[i] = i + 1; 22 } 23 R[m] = 0; L[0] = m; 24 size = m; 25 for (int i = 1; i <= n; i++)H[i] = - 1; 26 } 27 void Link(int r, int c) { 28 ++S[Col[++size] = c];//size像是每个点的编号 29 Row[size] = r; 30 D[size] = D[c]; 31 U[D[c]] = size; 32 U[size] = c; 33 D[c] = size; 34 if (H[r] < 0)H[r] = L[size] = R[size] = size; 35 else { 36 R[size] = R[H[r]]; 37 L[R[H[r]]] = size; 38 L[size] = H[r]; 39 R[H[r]] = size; 40 } 41 } 42 void remove(int c) { 43 L[R[c]] = L[c]; R[L[c]] = R[c]; 44 for (int i = D[c]; i != c; i = D[i]) 45 for (int j = R[i]; j != i; j = R[j]) { 46 U[D[j]] = U[j];//断开j 47 D[U[j]] = D[j]; 48 -- S[Col[j]]; 49 } 50 } 51 void resume(int c) { 52 for (int i = U[c]; i != c; i = U[i]) 53 for (int j = L[i]; j != i; j = L[j]) 54 ++S[Col[U[D[j]] = D[U[j]] = j]]; 55 L[R[c]] = R[L[c]] = c; 56 } 57 bool Dance(int d) { 58 if (R[0] == 0) { 59 for (int i = 0; i < d; i++)g[(ans[i] - 1) / 9] = (ans[i] - 1) % 9 + '1'; 60 for (int i = 0; i < N * N; i++)printf("%c", g[i]); 61 printf("\n"); 62 return true; 63 } 64 int c = R[0]; 65 for (int i = R[0]; i != 0; i = R[i]) 66 if (S[i] < S[c]) 67 c = i; 68 remove(c); 69 for (int i = D[c]; i != c; i = D[i]) { 70 ans[d] = Row[i]; 71 for (int j = R[i]; j != i; j = R[j])remove(Col[j]); 72 if (Dance(d + 1))return true; 73 for (int j = L[i]; j != i; j = L[j])resume(Col[j]); 74 } 75 resume(c); 76 return false; 77 } 78 }; 79 void place(int &r, int &c1, int &c2, int &c3, int &c4, int i, int j, int k) { 80 r = (i * N + j) * N + k; 81 c1 = i * N + j + 1; 82 c2 = N * N + i * N + k; 83 c3 = N * N * 2 + j * N + k; 84 c4 = N * N * 3 + ((i / 3) * 3 + (j / 3)) * N + k; 85 } 86 DLX dlx; 87 int main() { 88 while (scanf("%s", g) == 1) { 89 if (strcmp(g, "end") == 0)break; 90 dlx.init(N * N * N, N * N * 4); 91 int r, c1, c2, c3, c4; 92 for (int i = 0; i < N; i++) 93 for (int j = 0; j < N; j++) 94 for (int k = 1; k <= N; k++) 95 if (g[i * N + j] == '.' || g[i * N + j] == '0' + k) { 96 place(r, c1, c2, c3, c4, i, j, k); 97 dlx.Link(r, c1); 98 dlx.Link(r, c2); 99 dlx.Link(r, c3); 100 dlx.Link(r, c4); 101 } 102 dlx.Dance(0); 103 } 104 return 0; 105 }