NOIP2009 提高组 靶形数独

考虑搜索,我们提前把所有的条件处理好:每一行、每一列、每一块是否有数字 \(i\)。然后把初始给定的位置加到条件里面去,然后从左上往右下搜索,每次枚举当前位置填什么。加入当前位置的贡献。

然后我们需要加一个小优化:

不按照格子搜索。提前把所有的空格子处理出来,然后依次处理空格子。

这样的好处是不需要在跳过已经有答案的格子的时候递归,减少一些递归造成的贡献。

这样会 TLE,考虑加优化。

把从左上往右下搜改成从右下往左上搜就可以通过了。

为什么?考虑实质。我们跑的慢其实是因为 \(0\) 过于密集。当我们优先处理的行/列/宫 \(0\) 比较多的时候,就容易挂。而如果后处理它们,前面的就可能提供更多的限定来让它们跑的快一点。

而这个题的卡的数据都是左上 \(0\) 密集右下 \(0\) 稀疏没有右下 \(0\) 密集的数据所以我们就过了。

那么,这个做法还是很容易被卡的,考虑优化一下。

第一个尝试是随机排列处理的顺序,但这样反而会挂。因为还有一个暗藏的剪枝是我们每次处理一整行,前面的处理了,后面的情况就会越来越少,也就排除了更多的其他行的情况。但是如果我随机排列顺序,当前处理问题情况就会比较均匀,也就挂了。

但是不同行之间是没有太大影响的,即使是同一宫也很难提供很多有用的剪枝。所以我妈可以随机打乱行的处理顺序进行处理。

再进一步思考,其实我们只要安排 \(0\) 更少的行先处理就可以了,也就可以在最少的步骤提供最多的信息。

这就是我目前最快的算法。LOJ 的非打表最优解(luogu我看不到)似乎也是应用这个优化的搜索。

不过在我们中间第二个算法上还是有新的优化。我们发现,我们需要的是优先处理可能状态少的位置。而随机化将其均匀分布了。

然而,如果我们在一开始预处理每个位置在初始条件下能填的数的数目,按照这个来排序,就能获得不错的效果。

不过不管如何,这组数据依旧告诉我们这道题只是一道数据水的搜索题。

1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0

在所有有用的行都是 \(0\) 的情况下,所谓“先处理稀疏行”的优化就是完全无用的。但是貌似还没有什么程序能通过它。

posted @ 2023-06-01 16:47  jucason_xu  阅读(26)  评论(0编辑  收藏  举报