如果要自己手动解数独,我相信很多人都是会的,但是如何让电脑帮我们解数独呢?
最朴素的一个想法就是爆搜,但是爆搜的效率显然是很低的,我们要将问题进行转化再求解。
我们可以把数独的规则转化为4组条件:
1. 每行都要有1~9;
2. 每列都要有1~9;
3. 每个九宫格都要有1~9;
4. 每个格子都要填一个数。
这样一共要满足4×9×9 = 324个条件。
当我们填入一个数的时候,可以满足其中的4个条件,比如在(i, j)的位置上填入k,可以满足第i行有k、第j行有k、第(i/3)*3+(j/3)个九宫格中有k、第(i, j)这个格子中有数这4个条件。
填数的方法一共有9×9×9一共729种,我们需要从这729种填法中选出81种并且恰好能满足324个条件。
这样我们就将解数独转化成了一个精确覆盖问题。
我们可以用Dancing Links X(以下简称DLX)算法来解决精确覆盖问题。
DLX用一个十字循环链表维护了递归和回溯过程中的修改,大大提升了修改和回溯的效率,具体实现我就不再过多赘述。
下面给出我构造DLX的代码
for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) for (int k = 0; k < 9; k++) { if (puzzle[i][j] != 0 && puzzle[i][j] != k + 1) continue; int r = encode(i, j, k); solver.link(r, encode(0, i, j)); solver.link(r, encode(1, i, k)); solver.link(r, encode(2, j, k)); solver.link(r, encode(3, i / 3 * 3 + j / 3, k)); }
经过DLX优化后,在我本机跑1000组数独大概1.5s,1e6组大概要跑25分钟,我觉得还是有提升空间的。
欢迎各位dalao指点。