【笔记】小木棍 - 洛谷 P1120

发布时间 2023-08-11 13:09:14作者: purinliang

这道题是做dfs剪枝的,有几个明显的剪枝:

从最小的可能的长度开始枚举:因为题目是要求最小的答案,哪怕算出一个大的答案也还是要验证更小的答案不存在。
不需要验证只有一根木棍的情况。
木棍从大到小排序,因为小木棍的灵活性更好,这样做有利于减少搜索树根部的规模。(先搜索大木棍可以减少后续能选择的木棍的种类,也就是分叉更少,若存在答案可以更早返回,而且结合剪枝算法可以得到更好的剪枝效果)

有一个看起来难发现一点的剪枝:

剪枝1:如果是在拼同一根木棍的话,那么所用的组成成分必须按照非增序排列。(去掉重复的2+3=5和3+2=5的剪枝)

有两个特别难发现的剪枝:

剪枝2:如果某个状态下,当前长度为curLen,目标长度为targetLen,如果存在一根木棍长度恰好为targetLen-curLen,那么在这根木棍拼完之后,如果不能组成答案,则不必继续搜索更短的木棍。(这个优化的意思是,如果用一整根长的去搜都做不到,用几根短的再去搜,只会让组合的灵活性下降,属于可行性剪枝)。
剪枝3:如果当前长度curLen为0,那么这跟木棍拼完之后,如果不能组成答案,则不必继续搜索更短的木棍。(这个其实是在搜索树的根部剪掉一大刀,虽然看起来跟上面那个剪枝有点像(因为拼出targetLen之后curLen其实是归零的),但实际上剪枝的不是同一个部位)。这个剪枝的意思是:如果某个状态下,已经拼出了若干根完整的木棍,现在搜索一根全新的木棍的组合方法,那么枚举了最长的一个组分之后,若得到否定的结果,枚举次长的组分也是浪费时间(而且可能浪费得还不少,因为次长的可能可以组成完整的木棍了),因为剩余的木棍已经不支持组合出完整木棍了,因为对于一组完整的木棍来说,第一根选谁是一样的。

举一种奇葩的例子,比如说,目标长度是10,木棍们的长度是:

7 5 5 5 4 2 2 ,总长是30,显然长度为7的木棍是找不到对象的,然后整个搜索就应该退出了。但如果不加这个剪枝,则会变成:

5 - 5 成功,且组成新的木棍
7 - ? 失败, 5 - ? 失败, 4 - ? 失败, 2 - ? 失败

多搜索了4次。

当然这个例子还不够极端,如果 6 5 4 2 的数量再继续变多的话,浪费在后面的无效状态的时间会更多。

其实这个剪枝3是剪枝1的推广,也就是要求拼全新的木棍的时候,下一根木棍的开头不能比上一根木根的开头更短。