舞蹈链 学习小记
持续施工中。。。
前言
舞蹈连是用来解决精确覆盖问题的一种搜索方法。虽然它的最坏的时间复杂度未能改变,但是它的时间复杂度比较玄学,所以跑得还是比较快的。大概思想就是用十字链表来实现插入和删除。
思想
我们考虑我们需要解决以下问题:
- 给你一个\(n\)行\(m\)列的\(01\)矩阵,选出某些行使得选出的矩阵每一列有且仅有一个\(1\)
这其实就是上面说的精确覆盖问题。
可以想到的一点是,如果我们选出了某一行,那么,该行拥有\(1\)的所属列的拥有\(1\)的所属行都不能选。
举个例子,如果我们现在的矩阵长成这个样子:
如果我们选了第一行,那么,我们接下来能选的矩阵就是:
那么,如果我们删到最后矩阵已经没有了,但是仍然还有列未能覆盖到,那么显然那就是个不合法的覆盖,否则就是合法的。
于是,我们就发现这个东西涉及到的无非就是删列和删行,我们就可以用十字链表来维护了。
给出模板题的代码。但是舞蹈链的时间复杂度真的非常玄学,有的时候你换一下移动的方向都会影响时间,真的是看肤色的一种算法。
应用
其实舞蹈链主要解决的就是数独之类的,真的跑得贼快。
luogu P1074 靶形数独
题目大意
给出一个\(9\times 9\)的数独,有一些空已经填了,让你填上来,并求出最大贡献。
思路
应该算模板题吧。这里讲一下如何转换成精确覆盖问题。我们发现的是,我们可以用\((i,j,k)\)为列,表示第\(i\)行第\(j\)列为\(k\),行就是\((i,j),(i,k),(j,k),(bel,k)\),分别表示第\(i\)行第\(j\)列,第\(i\)行的\(k\),第\(j\)列的\(k\),第\(bel\)个九宫格的\(k\),限制的就是第\(i\)行第\(j\)列只能填一个数,第\(i\)行只能有一个\(k\),第\(j\)列只能有一个\(k\),第\(bel\)个九宫格只能有一个\(k\)。然后就是舞蹈链的模板了。
\(\texttt{Code}\)
luoguP4205 [NOI2005]智慧珠游戏
题目大意
有\(12\)种方块,填入一个\(10\times 10\)的三角形中,三角形中有的已经填了,求出一种合法的方法。
思路
据说暴力\(500^+\)行,瞬间感受到了\(\texttt{DLX}\)算法的优越性。
很显然,我们的限制条件就是每个方格只能填一个并且每种方块只能用且仅能用一次,所以列就是\(55+12\)列,行的话就是一个方块的填法,直接暴力枚举就好了,具体见代码。(发现好简洁啊)