精确覆盖问题:
有一个n行m列的01矩阵。
你要选一些行,使得每一列都有且仅有一个1。
数独转精确覆盖问题:
首先数独有四个限制:
1.每个格子能填也只能填一个数字。
2.每一行要填满九个数字。
3.每一列要填满九个数字。
4.每一宫要填满九个数字。
格子有9*9=81个,行列宫分别也有9个,每个要9个数字,所以一共有9*9*4列。
行的话也很简单。
一共9*9个格子,每个有9种填法,一共有9*9*9行。
*如果一个格子上已经有数字了,只往那个数字对应的一行加1。
暴力解决精确覆盖问题:
显然就是枚举行,找到行上有1的位置,找到有1的位置对应列,找到列上有1的位置,删掉整行。
然后变成子精确覆盖问题。
dancing-links优化精确覆盖问题:
发现上面这个递归过程贼难写,且常会用到不用的点多次。
dancing-links精确的说是数据结构,是个双向十字循环链表。
如图所示(盗图狗路过):
递归的第一步是判断head的右指针是否指向自己,如果是,就出解了。
不然找到head的右指针指向的点的下指针指向的点。
然后用链表的方法去删除。
还原也是用链表的方法去还原。
注意删除时如果是从左到右,还原一定要从右到左,不要想当然以为没有关系。
效率:
dancing-links除了优化一下递归的缓存, 在空间和时间上没有任何优势。
所以我们需要加—优—化。
感性认识(前辈经验)告诉我们,每次找1的个数较少的行会快一点。
事实上它不是快了一点,在有解的时候你是无法想象这个优化的作用之大的。
还有一个优化我们搜出来是一个行的集合,它是无序的,
针对这个,可以把一开始格子就有数字的格子提前搞掉,这样减少了矩阵规模。
裸题:
JZOJ 4373. 【GDOI2016模拟】数独
16*16的数独,300ms+
Code:
#include<cstdio>
#include<cstring>
#define f