Sudoku (数独)和精确覆盖

本文探讨了数独问题与精确覆盖的概念,包括精确命中和不同表示方法。重点介绍了如何利用矩阵和算法来实现数独中单元格的填数策略,其中关键在于通过设置d.M[i][j]为1来表示第j个空格在只考虑块约束时可填入数字i%9 + 1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

偶然看到《谈谈 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 void
append_right_tail(data_object *tail, data_object *p2);
static inline void
append_down_tail(data_object *tail, data_object *p2);
static void inline
init_data_obj(data_object *p);
static void inline
init_column_obj(struct column_object *c);

static inline void
free_resource(struct column_object *h);

static data_object *
create_dlx(int *matrix, int r, int c, struct column_object **h);

static int
search_dlx(struct column_object *h, int c, int k, data_object **out,
    int **r_out, int *r_cnt_out);

static inline void
cover_column(data_object *c);

static inline void
uncover_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 void
free_resource(struct column_object *h)
{
  free(h->data);
  free(h);
}

int
search(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 int
search_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 void
cover_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 void
uncover_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 void
append_right_tail(data_object *tail, data_object *p2)
{
	p2->l = tail;
	p2->r = tail->r;
	tail->r->l = p2;
	tail->r = p2;
}
static inline void
append_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 inline
init_data_obj(data_object *p)
{
	p->l = p->r = p->d = p->u = p;
}

static void inline
init_column_obj(struct column_object *c)
{
	data_object *p = c->data;
	init_data_obj(p);
	p->c = c;
	c->s = 0;
}


1. http://blog.youkuaiyun.com/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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值