zoukankan      html  css  js  c++  java
  • 折半搜索(meet in the middle)

    折半搜索(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储存的结果判断是否可行即可;

    总结

    ​ 我们面对一些其他算法很难处理的问题,要留住我们的本心 (根) ,优化暴力搜索,也许也会得到一个不错的复杂度.

  • 相关阅读:
    Scala中的构造器和高阶函数
    Scala中的元组
    Scala中的Map
    Scala中的If判断&While&For循环
    [改善Java代码]asList方法产生的List对象不可更改
    [改善Java代码]避开基本类型数组转换列表陷阱
    [改善Java代码]枚举和注解结合使用威力更大
    [改善Java代码]枚举项的数量限制在64个以内
    [改善Java代码]用枚举实现工厂方法模式更简洁
    [改善Java代码]在switch的default代码块中增加AssertionError错误
  • 原文地址:https://www.cnblogs.com/waterflower/p/11842561.html
Copyright © 2011-2022 走看看