Sudoku (数独)和精确覆盖

来源:互联网 发布:意大利淘宝 编辑:程序博客网 时间:2024/04/29 14:01
偶然看到《谈谈 Sudoku (数独)》[1]的博文,心血来潮把文章的算法实现了一番。有关Sudoku的具体介绍可参考维基百科。

具体解法有:回溯、精确匹配。回溯解法《谈谈 Sudoku (数独)》有比较详细的阐述,所以本文只记录一下精确覆盖的解法。


精确覆盖[2]

  • 1.精确覆盖
  •      给定集合X、S、T。S是X的子集的集合,T是S的子集,如果X中每个元素都只被T中的一个元素包含,那么T就是X的精确覆盖

  • 2.精确命中(exact hitting)
  •      给定集合X、S、Y。S是X的子集的集合,Y是X的子集,如果Y中每个元素都只被S中的一个元素包含,那么Y就是S的精确命中
  • 3.表示方法
  •      列表、矩阵
  • 4.实现
  •      Knuth's Algorithm X[3],解决精确覆盖的深度优先、递归、不确定算法。
         大概思想与技巧[4]:利用矩阵的表示方法,同时把行列表示成双向环列表(Dancing Link),在删除列表中的元素时,只更新前后(上下)的相关指针值。


数度到矩阵的转换
     Algorithm X使用了矩阵的表示方法,因此在需要把数度表示成矩阵的形式。具体转换如下:假设一个给定的9 * 9数度中,有N个空格需要求解,那么矩阵M的行数R=N * 9,列数C=4 * N。其中:
    a.M[i][j]=1, 0<=j<N,表示第j个空格考虑行、列、块以后可以取数字i%9 + 1
    b.M[i][j]=1, N<=j<2N,表示第j个空格只考虑行的情况下可以取数字i%9 + 1
    c.M[i][j]=1, 2N<=j<3N,表示第j个空格只考虑列的情况下可以取数字i%9 + 1

    d.M[i][j]=1, 3N<=j<4N,表示第j个空格只考虑块的情况下可以取数字i%9 + 1


代码如下:

#include <stdlib.h>#include <stdio.h>struct column_object;typedef struct data_obj_ {  struct data_obj_ *l, *r, *u, *d;  struct column_object *c;  int real_r;} data_object;typedef data_object list_header;struct column_object {  data_object* data;  int s;  int n;};static inline voidappend_right_tail(data_object *tail, data_object *p2);static inline voidappend_down_tail(data_object *tail, data_object *p2);static void inlineinit_data_obj(data_object *p);static void inlineinit_column_obj(struct column_object *c);static inline voidfree_resource(struct column_object *h);static data_object *create_dlx(int *matrix, int r, int c, struct column_object **h);static intsearch_dlx(struct column_object *h, int c, int k, data_object **out,    int **r_out, int *r_cnt_out);static inline voidcover_column(data_object *c);static inline voiduncover_column(data_object *c);static data_object *create_dlx(int *matrix, int r, int c, struct column_object **h){  int i, j, ele_cnt;  data_object *data, *right_most, *cur, *tail;  struct column_object *root;  for (i = 0, ele_cnt = 0; i < r; ++i)    for (j = 0; j < c; ele_cnt += matrix[i * c + j], ++j)      ;  data = (list_header *) malloc(sizeof(data_object) * (ele_cnt + 1 + c));  root = (struct column_object *) malloc(sizeof (struct column_object) * (c + 1));  *h = root;    root->data = data++;  init_column_obj(root);  root->s = r + 1;  for (i = 0, ++root; i < c; ++i, ++root) {    cur = root->data = data++;    init_column_obj(root);root->n = i;    append_right_tail((root - 1)->data, root->data);  }    for (i = 0; i < r; ++i) {    right_most = NULL;    for (j = 0; j < c; ++j) {      if (matrix[i * c + j] == 0) continue;      cur = data++;      cur->real_r = i;      if (right_most != NULL) {        append_right_tail(right_most, cur);      } else {        init_data_obj(cur);        right_most = cur;      }      tail = (*h + j + 1)->data->u;      append_down_tail(tail, cur);    }  }  return (*h)->data + c + 1;}static inline voidfree_resource(struct column_object *h){  free(h->data);  free(h);}intsearch(int *matrix, int r, int c, int **r_out, int *r_cnt_out){  struct column_object *h;  create_dlx(matrix, r, c, &h);  data_object **out = (data_object **) malloc(sizeof (data_object *) * r);  int ans = search_dlx(h, c, 0, out, r_out, r_cnt_out);  free_resource(h);  free(out);  return ans;}static intsearch_dlx(struct column_object *h, int c, int k, data_object **out,    int **r_out, int *r_cnt_out){  int c_it;  data_object *id_it, *sel_d, *jd_it;  if (h->data->r == h->data) {    for (c_it = 0; c_it < k; ++c_it)      (*r_out)[c_it] = out[c_it]->real_r;    *r_cnt_out = c_it;    return 0;  }  for (sel_d = h->data->d, id_it = sel_d->r;      id_it != sel_d; id_it = id_it->r)    if (sel_d->c->s > id_it->c->s)          sel_d = id_it;  /*conver column sel_d*/  cover_column(sel_d);  for (id_it = sel_d->d; id_it != sel_d; id_it = id_it->d) {    out[k] = id_it;    for (jd_it = id_it->r; jd_it != id_it; jd_it = jd_it->r)      cover_column(jd_it->c->data);    if (search_dlx(h, c, k + 1, out, r_out, r_cnt_out) == 0) return 0;    for (jd_it = id_it->l; jd_it != id_it; jd_it = jd_it->l)      uncover_column(jd_it->c->data);  }  uncover_column(sel_d);  return -1;}static inline voidcover_column(data_object *c){  data_object *i, *j;  c->r->l = c->l; c->l->r = c->r;  for (i = c->d; i != c; i = i->d) {    for (j = i->r; j != i; j = j->r) {j->d->u = j->u; j->u->d = j->d;j->c->s -= 1;    }  }}static inline voiduncover_column(data_object *c){  data_object *i, *j;  for (i = c->u; i != c; i = i->u) {    for (j = i->l; j != i; j = j->l) {j->c->s += 1;j->d->u = j; j->u->d = j;    }  }c->r->l = c; c->l->r = c;}static inline voidappend_right_tail(data_object *tail, data_object *p2){p2->l = tail;p2->r = tail->r;tail->r->l = p2;tail->r = p2;}static inline voidappend_down_tail(data_object *tail, data_object *p2){p2->c = tail->c;p2->u = tail;p2->d = tail->d;tail->d->u = p2;tail->d = p2;p2->c->s += 1;}static void inlineinit_data_obj(data_object *p){p->l = p->r = p->d = p->u = p;}static void inlineinit_column_obj(struct column_object *c){data_object *p = c->data;init_data_obj(p);p->c = c;c->s = 0;}


1.http://blog.csdn.net/Solstice/article/details/2096209
2.http://en.wikipedia.org/wiki/Exact_cover
3.http://en.wikipedia.org/wiki/Knuth%27s_Algorithm_X
4.http://lanl.arxiv.org/PS_cache/cs/pdf/0011/0011047v1.pdf
原创粉丝点击