zoukankan      html  css  js  c++  java
  • alias method/别名算法

    alias method/别名算法

    前言

    一个在oi/acm比较少见的算法吧。。

    从问题开始QAQ

    (N(N>1))个物品,有属性(d_i),现在要平均放进(N-1)个盒子里,每个盒子最多存在两个物品,物品可以分割。

    当N=2时。

    显然两个全放进一个盒子里就行了。

    当N>2时。

    显然我们可以先算出每个盒子需要放多少,设其为(K),于是(sum{d_i}=(N-1)K)
    一共(N)个物品要放进(N-1)个盒子中,设其中(d_i)的最大值为(mx),最小值为(mn)
    性质1:(mn<K)
    性质2:(mn+mx>K)
    这两个性质比较显然,都可以用反证法证明的。
    于是我们可以直接让(mn)和部分(mx)来凑成K,多余部分放回去,于是物品和盒子可数均减少1,递归即可。

    怎么实现

    我们需要维护增加元素,删除元素,询问最大最小值的一个数据结构,显然可以用个multiset,于是就能轻松做到O(nlogn)。

    进一步优化

    如果要维护最大最小值的话,就很难不带log。(悲)。然而实际上我们也并非必须取最值。
    我们考虑把物品分成两类,一类是(d_i<K),其余是另一类。
    于是我们可以每次在两个类中各取一个凑一个K,然后放回剩余。
    然而这么做会有个问题,到后面可能存在所有(d_i)全都小于(K)的情况。
    其实这个情况下可以证明任意两个物品都能满足加起来不小于K(就不证了吧QAQ),于是按顺序合并就好。
    于是现在的做法就可以做到空间O(n),时间O(n)了。

    应用

    一个随机事件包含(n)种情况,每种情况发生的概率分别为:(p_i),问怎么用产生符合这个概率的采样方法。
    这种问题的解决方法很多,比如按照概率构造数组然后在上面随机。。
    然而许多方法时间空间复杂度不够优秀,或者在大量数据采样时不能较好的符合发生概率。
    应用别名算法,相当于是把这些总和为1的物品分到n-1的盒子里,每次采样先随机到一个盒子,再按照盒子内的比例随机一次。
    就能做到O(n)的空间和时间预处理,每次O(1)的采样,并且采样结果比较符合事件概率。

  • 相关阅读:
    Java程序员从笨鸟到菜鸟全部博客目录
    Problem I
    Problem I
    Problem S
    Problem S
    Problem X
    Problem X
    Problem Q
    Problem Q
    Ellipse
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/14694638.html
Copyright © 2011-2022 走看看