任意一个像素,必须在三个方向上保证值唯一。这三个方向分别是X,Y,BOX。XY很好理解就是纵横的一条线(X,Y的像素个数就是N)。BOX指这个像素所在的BOX(BOX是由 (N的平方根)*(N的平方根) 个像素组成的矩阵)。

如图,一个9*9个像素的数独。(我把基数称为3)

1616的数独,16行,16列。同时分成44个BOX。(我把基数称为4)

那么如何生成一个有解的数独呢?

这个方法可行吗?

以下方法是按从左到右,从上到下的顺序来生成随机数的,看起来可行,实际上大多数情况下都无法生成有解数独,因为前面还比较容易满足条件,后面基本上就无法满足条件了。

以上方法最大的问题是,因为是左右,前后顺序在生成数独,实际上越到后面,会导致可以填充的满足XYB约束值越少,甚至没有。

而是每一步都选择在XYB方向上还有最大概率(即最多没有填充的值)的像素。(我不清楚下围棋先占4个角,是不是也是同样的道理?)

输入一个矩阵,得到另一个矩阵,表示当前位置在XYB轴的未填充值的个数。(非空值的xyb返回x,y,0,0,0)因为非空值不需要再填充它,所以无所谓。

1、首先要创建一个类型,包括数独矩阵的 X,Y坐标。以及这个坐标的横、竖、BOX三个方向上的剩余未填充值的个数。

  1. ax int, -- 横坐标
  2. ay int, -- 纵坐标
  3. x int, -- 横向还有多少未填充像素
  4. y int, -- 竖向还有多少未填充像素
  5. b int -- BOX内还有多少未填充像素
  6. );

2、编写一个函数,用来计算一个为完成数独矩阵,其每一个像素的XYB值。

3、用法举例

计算以下2为基数,4*4的矩阵的xyb值

  1. {0,1,1,0}
  2. {0,1,1,0}

使用unnest可以解开,按XYB三个方向总大小排序,再按某个方向最大排序,从而做到逐级收敛,真正每一次填充的像素,都是具备最大概率的像素。

  1. postgres=# select * from
  2. unnest(
  3. comp_xyb('{ {1,2,3,4},{0,1,1,0},{0,1,1,0},{0,1,1,0} }', 2)
  4. ) t
  5. where
  6. t.x+t.y+t.b <> 0
  7. order by
  8. greatest(t.x,t.y,t.b) desc;
  9. ax | ay | x | y | b
  10. ----+----+---+---+---
  11. 3 | 1 | 2 | 3 | 2
  12. 3 | 4 | 2 | 3 | 2
  13. 4 | 1 | 2 | 3 | 2
  14. 4 | 4 | 2 | 3 | 2
  15. 2 | 1 | 2 | 3 | 1
  16. 2 | 4 | 2 | 3 | 1

通过这个SQL得到了某个像素,这个像素的XYB方向上,还有最多的像素没有被填充。

用AX,ZY坐标值,往矩阵的这个像素填充符合数独条件的随机值,可以大幅提高构造可解数独的概率。

本文先介绍如何得到这样的一个像素,填充一个值进行,这个值的取值区间应该是最大的(最不会与数独的游戏规则违背),从而更大可能的生成一个完整可解的数独。

下面一篇文章再介绍如何生成一个N*N的数独。

http://poj.org/problem?id=3074

NP完全问题近似求解。

《PostgreSQL 生成任意基数数独 - 3》