Sudoku

终于搞定了,开敲以前,我还在位建图而发愁呢,呵呵

DLX的经典应用:解决数独问题

momodi的论文写的真是不错

建图方式(就是01矩阵)如下

行:
一共9 * 9 * 9 == 729行。一共9 * 9小格,每一格有9种可能性(1 - 9),每一种可能都对应着一行。
列:

一共(9 + 9 + 9) * 9 + 81 == 324 种前面三个9分别代表着9行9列和9小块,乘以9的意思是9种可能(1 - 9),因为每种可能只可以选择一个。81代表着81个小格,限制着每一个小格只放一个数字。

 

读入数据后,如果为'.',则建9行,即有1-9种可能,否则建一行,表示某小格只能放确定的某个数字。

建完图,加一份模板就可以过了。

代码
1 /*DLX解决sudoku问题,转化为729*324的精确覆盖问题*/
2 #include<stdio.h>
3 #include<string.h>
4  #define INF 0x3fffffff
5  #define NN 330
6 #define MM 740
7 int N, M;
8 int cntc[NN];
9 int L[NN * MM], R[NN * MM], U[NN * MM], D[NN * MM], C[NN * MM];
10 int head;
11 int adj[MM][NN];
12 int ans[10][10];
13
14 /*删除第c列*/
15 void remove(int c){
16 L[R[c]] = L[c];
17 R[L[c]] = R[c];
18
19 int i, j;
20 for (i = D[c]; i != c; i = D[i]){
21 for (j = R[i]; j != i; j = R[j]){
22 U[D[j]] = U[j];
23 D[U[j]] = D[j];
24 cntc[C[j]]--;
25 }
26 }
27 }
28 /*恢复第c列*/
29 void resume(int c){
30 L[R[c]] = c;
31 R[L[c]] = c;
32
33 int i, j;
34 for (i = D[c]; i != c; i = D[i]){
35 for (j = R[i]; j != i; j = R[j]){
36 U[D[j]] = j;
37 D[U[j]] = j;
38 cntc[C[j]]++;
39 }
40 }
41 }
42 int dfs(){
43
44 if (R[head] == head) return 1;
45
46 int min = INF;
47 int c, i, j;
48 for (i = R[head]; i != head; i = R[i]){
49 if (cntc[i] < min){
50 c = i;
51 min = cntc[i];
52 }
53 }
54 remove(c);
55 for (i = D[c]; i != c; i = D[i]){
56 //O[idx++] = (i - 1) / M;
57 int r = (i - 1) / N;
58 int num = (r + 8) / 9;
59 int key = r % 9;
60 if (key == 0) key = 9;
61 int x = (num + 8) / 9;
62 int y = num % 9;
63 if (y == 0) y = 9;
64 ans[x][y] = key;
65
66 for (j = R[i]; j != i; j = R[j]){
67 remove(C[j]);
68 }
69 if (dfs()) return 1;
70 /*这个顺序很重要,删除和恢复的方向必须相反
71 开始相同,都是向右的,结果TLE了*/
72 for (j = L[i]; j != i; j = L[j]){
73 resume(C[j]);
74 }
75 }
76 resume(c);
77 return 0;
78 }
79
80 /*建图*/
81 int Build(){
82 int i, j, now, pre, first;
83 head = 0;
84 for (j = head; j < N; j++){
85 R[j] = j + 1;
86 L[j + 1] = j;
87 }
88 L[head] = j;
89 R[j] = head;
90
91 /*列双向链表*/
92 for (j = 1; j <= N; j++){
93 pre = j;
94 cntc[j] = 0;
95 for (i = 1; i <= M; i++){
96 if (adj[i][j]){
97 now = i * N + j;
98 C[now] = j;
99 cntc[j]++;
100 D[pre] = now;
101 U[now] = pre;
102 pre = now;
103 }
104 }
105 now = j;
106 D[pre] = now;
107 U[now] = pre;
108 if (cntc[j] == 0) return 0;
109 }
110 /*行双向链表*/
111 for (i = 1; i <= M; i++){
112 pre = first = -1;
113 for (j = 1; j <= N; j++){
114 if (adj[i][j]){
115 now = i * N + j;
116 if (pre != -1){
117 R[pre] = now;
118 L[now] = pre;
119 }else{
120 first = now;
121 }
122 pre = now;
123 }
124 }
125 if (first != -1){
126 now = first;
127 R[pre] = now;
128 L[now] = pre;
129 }
130 }
131 return 1;
132 }
133
134 int main()
135 {
136 char str[85];
137 int i, j, k;
138 while(scanf("%s", str) != EOF){
139 if (strcmp(str, "end") == 0) break;
140
141 memset(adj, 0, sizeof(adj));
142 for (i = 1; i <= 9; i++){
143 for (j = 1; j <= 9; j++){
144 int t = 9 * (i - 1) + j;
145 //for (l = 1; l <= 9; l++){
146 // adj[9 * (t - 1) + l][t] = 1;
147 if (str[t - 1] == '.'){
148 for (k = 1; k <= 9; k++){
149 // adj[t][k] = 1;
150 adj[9 * (t - 1) + k][t] = 1;
151 adj[9 * (t - 1) + k][81 + (i - 1) * 9 + k] = 1; // row
152 adj[9 * (t - 1) + k][162 + (j - 1) * 9 + k] = 1;// col
153 adj[9 * (t - 1) + k][243 + ((i - 1) / 3 * 3 + (j + 2) / 3 - 1) * 9 + k] = 1;// grid
154 }
155 }else{
156 k = str[t - 1] - '0';
157 adj[9 * (t - 1) + k][t] = 1;
158 adj[9 * (t - 1) + k][81 + (i - 1) * 9 + k] = 1; // row
159 adj[9 * (t - 1) + k][162 + (j - 1) * 9 + k] = 1;// col
160 adj[9 * (t - 1) + k][243 + ((i - 1) / 3 * 3 + (j + 2) / 3 - 1) * 9 + k] = 1;// grid
161 }
162 // }
163 }
164 }
165 M = 729;
166 N = 324;
167 Build();
168 dfs();
169 for(i = 1; i <= 9; i++){
170 for(j = 1; j <= 9; j++) printf("%d", ans[i][j]);
171 }
172 puts("");
173 }
174 return 0;
175 }
176

 

posted on 2010-10-06 10:37  ylfdrib  阅读(1805)  评论(0编辑  收藏  举报