随机抽数的概率误区与洗牌算法
在重新做《复杂》一书中第九章提到的遗传算法例子的时候遇到了一个问题,遗传算法驱动的机器人罗比需要在不断的进化过程中产生出可以清理10X10方格内随机位置垃圾的最优策略。
10X10方格内的垃圾是随机放置的,假设需要随机放置50个垃圾的话,并视10X10网格为长度为100的线性空间,这就需要伪随机数函数参与从0 ~ 99共100个数字中选出50个不重复的数字作为标号。
最开始没经过思考,我是这样做的:
原理就是反复从0 ~99之中随机抽取,如果抽到已经抽中的数字的话会重新抽,说实话,这样的思路很丑,因为会存在一直抽重复数字的情况,但是实际上几乎不会如此,而且效率并不低。
后来和别人讨论改写了方法
这种方法的思路是建立一个内容为自身下标的数组,之后依次把每一个元素与全局范围内随机选取的元素交换,这样就产生了一个随机的乱序数组,假设上文之中长度为100的数组经过乱序之后,取前50个元素的值就可以作为垃圾随机放置的位置。
但是这种做法是错误的,因为概率不等。
最初我简化了问题规模,改为10选5,这是程序统计出来的0 ~ 9被选中为前5的次数分布。
做了一千万次运算,可以看出5被选中的概率是最大,9被选中的概率是最小,而且波动是百万量级的,肯定有问题。
之后听取别人建议用了洗牌算法。
只是略加改动,思路是依次选取数组之中每一个元素与尾部未乱序序列中随机抽取的元素交换。同样是做一千万次运算,结果得出了大致正确的分布。
再一次把问题规模简化,简化成为3选1,这次是做一百万次运算。
其实最初我也考虑到了概率不等,但是我想了一下元素为两个的情况,也就是2选1,对于这种情况,如果使用此方法的话概率是相等的,于是想当然的扩展到了任意长度上,事实证明这是错误的。
当长度缩短到为3的时候,就可以很轻易的画出树状图。
对于3选1来说,0被选中的概率是9/27,1被选中的概率是10/27,2被选中的概率是8/27。让人大跌眼镜啊,这种想当然的方法产生的果然是概率不等的结果。
然后有没有一句话可以一针见血的说出这种现象产生的运作原因呢?