您的位置:首页 > 其它

poj3074 Sudoku 转化为精确覆盖问题 DLX

2010-10-06 10:37 417 查看
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种可能,否则建一行,表示某小格只能放确定的某个数字。

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

代码

/*DLX解决sudoku问题,转化为729*324的精确覆盖问题*/
#include<stdio.h>
#include<string.h>
#define INF 0x3fffffff
#define NN 330
#define MM 740
int N, M;
int cntc[NN];
int L[NN * MM], R[NN * MM], U[NN * MM], D[NN * MM], C[NN * MM];
int head;
int adj[MM][NN];
int ans[10][10];

/*删除第c列*/
void remove(int c){
L[R[c]] = L[c];
R[L[c]] = R[c];

int i, j;
for (i = D[c]; i != c; i = D[i]){
for (j = R[i]; j != i; j = R[j]){
U[D[j]] = U[j];
D[U[j]] = D[j];
cntc[C[j]]--;
}
}
}
/*恢复第c列*/
void resume(int c){
L[R[c]] = c;
R[L[c]] = c;

int i, j;
for (i = D[c]; i != c; i = D[i]){
for (j = R[i]; j != i; j = R[j]){
U[D[j]] = j;
D[U[j]] = j;
cntc[C[j]]++;
}
}
}
int dfs(){

if (R[head] == head) return 1;

int min = INF;
int c, i, j;
for (i = R[head]; i != head; i = R[i]){
if (cntc[i] < min){
c = i;
min = cntc[i];
}
}
remove(c);
for (i = D[c]; i != c; i = D[i]){
//O[idx++] = (i - 1) / M;
int r = (i - 1) / N;
int num = (r + 8) / 9;
int key = r % 9;
if (key == 0) key = 9;
int x = (num + 8) / 9;
int y = num % 9;
if (y == 0) y = 9;
ans[x][y] = key;

for (j = R[i]; j != i; j = R[j]){
remove(C[j]);
}
if (dfs()) return 1;
/*这个顺序很重要,删除和恢复的方向必须相反
开始相同,都是向右的,结果TLE了*/
for (j = L[i]; j != i; j = L[j]){
resume(C[j]);
}
}
resume(c);
return 0;
}

/*建图*/
int Build(){
int i, j, now, pre, first;
head = 0;
for (j = head; j < N; j++){
R[j] = j + 1;
L[j + 1] = j;
}
L[head] = j;
R[j] = head;

/*列双向链表*/
for (j = 1; j <= N; j++){
pre = j;
cntc[j] = 0;
for (i = 1; i <= M; i++){
if (adj[i][j]){
now = i * N + j;
C[now] = j;
cntc[j]++;
D[pre] = now;
U[now] = pre;
pre = now;
}
}
now = j;
D[pre] = now;
U[now] = pre;
if (cntc[j] == 0) return 0;
}
/*行双向链表*/
for (i = 1; i <= M; i++){
pre = first = -1;
for (j = 1; j <= N; j++){
if (adj[i][j]){
now = i * N + j;
if (pre != -1){
R[pre] = now;
L[now] = pre;
}else{
first = now;
}
pre = now;
}
}
if (first != -1){
now = first;
R[pre] = now;
L[now] = pre;
}
}
return 1;
}

int main()
{
char str[85];
int i, j, k;
while(scanf("%s", str) != EOF){
if (strcmp(str, "end") == 0) break;

memset(adj, 0, sizeof(adj));
for (i = 1; i <= 9; i++){
for (j = 1; j <= 9; j++){
int t = 9 * (i - 1) + j;
//for (l = 1; l <= 9; l++){
//    adj[9 * (t - 1) + l][t] = 1;
if (str[t - 1] == '.'){
for (k = 1; k <= 9; k++){
// adj[t][k] = 1;
adj[9 * (t - 1) + k][t] = 1;
adj[9 * (t - 1) + k][81 + (i - 1) * 9 + k] = 1; // row
adj[9 * (t - 1) + k][162 + (j - 1) * 9 + k] = 1;// col
adj[9 * (t - 1) + k][243 + ((i - 1) / 3 * 3 + (j + 2) / 3 - 1) * 9 + k] = 1;// grid
}
}else{
k = str[t - 1] - '0';
adj[9 * (t - 1) + k][t] = 1;
adj[9 * (t - 1) + k][81 + (i - 1) * 9 + k] = 1; // row
adj[9 * (t - 1) + k][162 + (j - 1) * 9 + k] = 1;// col
adj[9 * (t - 1) + k][243 + ((i - 1) / 3 * 3 + (j + 2) / 3 - 1) * 9 + k] = 1;// grid
}
// }
}
}
M = 729;
N = 324;
Build();
dfs();
for(i = 1; i <= 9; i++){
for(j = 1; j <= 9; j++) printf("%d", ans[i][j]);
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: