poj3076 Sudoku DLX

Sudoku

同样是一道dancing links,和poj3074同样是数独问题,只要稍稍改下就能过,我上篇文章里用的是矩阵存储方式,套到这里居然MLE了,只好重新处理,处理过程还是比较麻烦的,终于搞定了,呵呵。这里我给模板化了,能够很容易的处理数独这一类问题

 

代码
   
     
1 /* DLX解决sudoku问题,转化为MM * NN的精确覆盖问题 */
2   // 解决LL * LL的Sudoku问题
3   #include < stdio.h >
4 #include < math.h >
5 #include < stdlib.h >
6 #include < string .h >
7 #define INF 0x3fffffff
8 #define LL 16
9 #define X 2
10 #define MM (LL * LL * LL)
11 #define NN (LL * LL * 4)
12
13 const int SQ = ( int )(sqrt( 1.0 * LL));
14 int N, M;
15 int cntc[NN + X]; // 记录列节点个数
16 int head;
17 int num;
18 char ans[LL + X][LL + X]; // 存储最后结果
19
20 struct node{
21 int l, r, u, d, x, y, n, c; // c表示当前节点所在列, ans[x][y] = n
22 void set ( int _l, int _r, int _u, int _d, int _x, int _y, int _n, int _c){
23 l = _l; r = _r; u = _u; d = _d; x = _x, y = _y, n = _n, c = _c;
24 }
25 }f[MM * 4 + NN + X];
26
27 void Add( int _l, int _x, int _y, int _n, int c){
28 f[ ++ num].x = _x;
29 f[num].y = _y;
30 f[num].n = _n;
31 f[f[num].l = _l].r = num;
32 f[f[num].u = f[c].u].d = num;
33 f[f[num].d = f[num].c = c].u = num;
34 cntc[c] ++ ;
35 }
36 void Addrow( int i, int j, int k){ // 如果ans[i][j] = k
37 int t = (i - 1 ) * LL + j;
38 Add(num + 4 , i, j, k, t);
39 Add(num, i, j, k, LL * LL + (i - 1 ) * LL + k);
40 Add(num, i, j, k, 2 * LL * LL + (j - 1 ) * LL + k);
41 Add(num, i, j, k, 3 * LL * LL + ((i - 1 ) / SQ * SQ + (j + SQ - 1 ) / SQ - 1 ) * LL + k);
42 }
43 /* 删除第c列 */
44 void remove( int c){
45 f[f[c].r].l = f[c].l;
46 f[f[c].l].r = f[c].r;
47
48 int i, j;
49 for (i = f[c].d; i != c; i = f[i].d){
50 for (j = f[i].r; j != i; j = f[j].r){
51 f[f[j].d].u = f[j].u;
52 f[f[j].u].d = f[j].d;
53 cntc[f[j].c] -- ;
54 }
55 }
56 // printf("remove %d\n", c);
57 }
58 /* 恢复第c列 */
59 void resume( int c){
60 f[f[c].r].l = c;
61 f[f[c].l].r = c;
62
63 int i, j;
64 for (i = f[c].d; i != c; i = f[i].d){
65 for (j = f[i].r; j != i; j = f[j].r){
66 f[f[j].d].u = j;
67 f[f[j].u].d = j;
68 cntc[f[j].c] ++ ;
69 }
70 }
71 // printf("resume %d\n", c);
72 }
73 int dfs(){
74 if (f[head].r == head) return 1 ;
75 int min = INF;
76 int c, i, j;
77 for (i = f[head].r; i != head; i = f[i].r){
78 if (cntc[i] < min){
79 c = i;
80 min = cntc[i];
81 }
82 }
83 remove(c);
84 for (i = f[c].d; i != c; i = f[i].d){
85 ans[f[i].x][f[i].y] = f[i].n; // 每选中一行相当于填一小格
86
87 for (j = f[i].r; j != i; j = f[j].r){
88 remove(f[j].c);
89 }
90 if (dfs()) return 1 ;
91 /* 这个顺序很重要,删除和恢复的方向必须相反
92 开始相同,都是向右的,结果TLE了 */
93 for (j = f[i].l; j != i; j = f[j].l){
94 resume(f[j].c);
95 }
96 }
97 resume(c);
98 return 0 ;
99 }
100
101 int main()
102 {
103 int i, j, k;
104 char s[LL + X][LL + X];
105 int ca = 0 ;
106 while (scanf( " %s " , s[ 0 ]) != EOF){
107 if (ca) puts( "" );
108 ca ++ ;
109 for (i = 1 ; i < LL; i ++ ){
110 scanf( " %s " , s[i]);
111 }
112 M = MM;
113 N = NN;
114 num = N;
115 for (i = 1 ; i < N; i ++ ){
116 f[i]. set (i - 1 , i + 1 , i, i, 0 , 0 , 0 , i);
117 }
118 f[ 0 ]. set (N, 1 , 0 , 0 , 0 , 0 , 0 , 0 );
119 f[N]. set (N - 1 , 0 , N, N, 0 , 0 , 0 , N);
120
121 memset(cntc, 0 , sizeof (cntc));
122 for (i = 1 ; i <= LL; i ++ ){
123 for (j = 1 ; j <= LL; j ++ ){
124 if (s[i - 1 ][j - 1 ] == ' - ' ){
125 for (k = 1 ; k <= LL; k ++ ){
126 Addrow(i, j, k);
127 }
128 } else {
129 k = s[i - 1 ][j - 1 ] - ' A ' + 1 ;
130 Addrow(i, j, k);
131 }
132 }
133 }
134 dfs();
135 for (i = 1 ; i <= LL; i ++ ){
136 for (j = 1 ; j <= LL; j ++ ) printf( " %c " , ans[i][j] + ' A ' - 1 );
137 puts( "" );
138 }
139 }
140 return 0 ;
141 }
142

 

你可能感兴趣的:(sudo)