折半搜索(meet in the middle)
? 我们经常会遇见一些暴力枚举的题目,但是由于时间复杂度太过庞大不得不放弃.
? 由于子树分支是指数性增长,所以我们考虑将其折半优化;
前言
? 这个知识点曾经在模拟赛中出现过,所以这里稍微提一下;
? 讲的很浅显,但是不要D讲者;
入门
? dfs搜索树是指数性增长,如果将指数减少一半,就将会有量的飞跃,所以在遇见暴力枚举太大时,我们可以考虑这种算法;
? 总体思想即,dfs搜素通常从一个点出发,遍历所有深度,那么我们考虑将深度减半,从两个点出发,然后分别统计两边dfs时的信息,整合即可;
注意
? 该算法能否使用的关键是整合,两个深度是否能整合在一起需要思考;
了解
? 我们通过一道例题来讲解;
? 有一个体积为 \(m\) \((m<=1e18)\) 的背包,有 \(n\) \((n<=40)\) 个物品,问装背包有多少种方案.
? 若 \(m\) 较小时,该题即一个裸的背包,但本题 \(m<=1e18\) 背包就会不可做 (我不会) ;
? 那么考虑最基础的方法,暴力枚举每一种情况,然后统计即可.
? 直接枚举会导致超时,我们可以考虑双向搜索,将物品截半,将第一次搜索时的情况存下来,排序,第二次搜索时,找到一个结果,二分查找第一次的情况,计数即可;
?
给 \(n\) \((n<=20)\) 个数,从中任意选出一些数,使这些数能分成和相等的两组。
求方案数.
? 我们同样考虑两遍dfs,分别整理出两次搜索的结果,但是整合时有些麻烦;
? 整合时,我们可以暴力计数,考虑到这些数的随机性,所以期望得分 \(100\) ,但是如果出题人精心手造数据,就会有些凉凉;
? 考虑每种情况只会有 \(1\) 的贡献,那么我们将 \(2^{20}\) 种情况分别跑出来,用两次dfs储存的结果判断是否可行即可;
总结
? 我们面对一些其他算法很难处理的问题,要留住我们的本心 (根) ,优化暴力搜索,也许也会得到一个不错的复杂度.
原文地址:https://www.cnblogs.com/waterflower/p/11842561.html