题意:给一个由(n+1)*n*2根火柴棒构成的边长为n正方形,每根火柴棒都有编号,已经删去了k根火柴棒,问至少再删多少根火柴棒可以破坏掉所有正方形。 【刘汝佳:《算法竞赛入门经典(第二版)》 P213】
【小吐槽】
感觉做这道题的历程真是哔了狗了。一开始自己写了个暴搜果断就T了,主要是判断每个正方形存在与否的方法太暴力。之后在网上看到很多人都写的DLX,被如何记录正方形存在的方式恶心到的我下狠心决定学一学DLX。一开始看刘汝佳叔叔的书,懂了大概原理,不过他的书上的代码是精确覆盖的,而这道题是可重复覆盖。所以自己得yy代码,yy+copy网上其他。然而被DLX搞了2天时间,还是有问题,写出来的样例都过不了,哎,还是自己太弱的过。暂时还不适合学这种高大上的东西T^T。无奈了,调DLX代码调的头疼了,决定再写一遍IDA*,沿用了一些表示正方形的特殊技巧,刚刚写完之后抱着肯定会Wa的心态随便交了一下,0ms AC。
那么就是说,这道题我是用的是IDA*,并没有用高大上的舞蹈链。
估价函数还是很好想的,麻烦就麻烦在如何判断在一个状态下还剩哪些正方形。感觉对于乱搞能力强的这个问题都不是事。
我们开两个数组stick[][], square[][] (我用的是vector), stick[i]表示的是需要编号为i的木棒的正方形有哪些,square[i]表示的是编号为i的正方形需要的木棒有哪些。
exi[i]表示的是编号i的正方形是否存在:exi[i] == 0, 存在;每删去该正方形上的一根火柴,exi[i]–。这么做就解决了递归、回溯的问题。
观察一下木棒的编号规律,提前预处理出来正方形们以及木棒们(square,stick两个数组),开始搜索,找到一个还存在的正方形,枚举删除它的哪一根木棒,递归。为了节省时间,要找还存在的边长最小的正方形,这个在我们预处理square数组时,加入正方形的顺序就可以搞定。
估价函数:对于当前一个状态,枚举每个正方形是否存在,如果存在,就删除它的所有木棍,同时res++,然后继续枚举,最后返回res。 这个估价函数和poj 2032 IDA*做法用的那个估价函数很相似。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
usi