蓄水池算法

基本介绍

有一个流,里面放着 1, 2, 3,... n 号球。还有一个可以装下 M 个球的袋子。我们通过一个按钮控制流中球的流出。当流出一个球的时候,我们可以通过一个机制 1 选择淘汰当前的球或者将球放入袋子,若袋子容量有剩余,就可以直接加入,若袋子已满则需要通过机制 2 选择一个球拿出袋子。中途被拿出的球视为彻底消失,永远不再复用。
求机制 1 和机制 2 ,使得当流出到第 i 号球的时候,1 到 i 号球在袋子里的概率相等。

机制 1

通过概率来选择,此时流出的球为第 k 个,那么该球入袋的概率就为 \(\frac{10}{k}\)

机制 2

等概率的随机弹出一个球,若袋子的容量为 M,那么每个球弹出的概率就为 \(\frac{1}{M}\)

正确性证明

例证

假设,\(M=10\)。当 \(k \le 10\) 时,我们将球全部入袋。
\(k > 10\) 时,我们假设 \(k=11\),那么首先当前的球有 \(\frac{10}{11}\) 的概率入袋子。我们考虑 3 号球还在袋子里的概率:
假如 11 号球进入了袋子,那么就必须弹出一个袋子里的球,所以弹出 3 号球的概率就为 \(\frac{1}{10}\),于是,3 号球仍然在袋子里的概率就为 \(1 - \frac{10}{11} \times \frac{1}{10} = \frac{10}{11}\).
同理,假如 12 号 k=12,那么 3 号球仍在袋子中的概率就为 \(\frac{10}{11} \times \frac{11}{12} = \frac{10}{12}\),k=13,概率就为 \(\frac{12}{13} \times \frac{10}{12} = \frac{10}{13}\) ,由此我们推出当 k=i 时,3 号球还在袋子里的概率就为:

\[\frac{10}{11} \times \frac{11}{12} \times \frac{12}{13} \times ... \times \frac{i-1}{i} = \frac{10}{i} \]

正式证明

对例证进行推广,假如我们不考虑 3 号球,袋子的容量为 M,那么我们可以类比的得到当 k=i 时,1 到 i 号球在袋子中的概率就为:\(\frac{M}{i}\),满足题意。

应用

蓄水池算法的一个常用的应用就是抽奖系统。
假设我们有一个需求:
实现一个抽奖机制:总共有 100 个名额,候选人是某一天的登录用户的集合。但是要求在第二天刚刚到来的时候,就公布抽奖结果。例如,抽奖时间是 11 月 24 日 0 点到 11 月 25 日零点,那么就要求在 11 月 25 日零点公布抽奖结果。
我们一个简单的实现就是通过数据库得到那一天所有登录用户的名单,再通过随机程序得到那 100 个人,但是这就无法做到零点公布了!
我们利用蓄水池算法。在那一天登录的用户就是那个流,每个人就是那 1 到 n 的球,袋子的容量就是 100 ,将最后还留在袋子的人视为中奖者。于是当流出到第 i 个人的时候,1 到 i 个人留在袋子中的概率(中奖的概率)就是相等的,也就是说,每个人是完全公平的。
若流出的时候,我们那个人恰好连进袋子的机会都没有,那个人就与中奖无缘了。若袋子中的某个人 B 很不幸被流出的那个人 A 弹出了,那么被弹出的 B 也和获奖无缘了。

posted @ 2022-11-24 18:33  yelanyanyu  阅读(191)  评论(0)    收藏  举报