问题一:
已知一随机发生器,产生0的概率是p,产生1的概率是1-p,现在要你构造一个发生器,使得它构造0和1的概率均为1/2;
构造一个发生器,使得它构造1、2、3的概率均为1/3;…,
构造一个发生器,使得它构造1、2、3、…n的概率均为1/n,要求复杂度最低。
解决方法:
原始的随机数生成器,生成0 的概率为p,生成1的概率为1-p,那么怎么构造才能使得生成0和1的概率相等呢。或者说有两个独立的事件的概率是相等呢?
这样来做一下,让该随机数生成器生成两个数,那么序列是00,01,10,11概率分别为 p*p,p(1-p),(1-p)p,(1-p)*(1-p)
很明显,这四种情况中存在两个独立的事件概率是相等。也就是01和10,那么我把01看成是0,10看成是1,那么他们输出的概率均为p(1-p),其他的情况舍弃。这样就得到了0和1均等生成的随机器了。
这种解法可以推广到n个数的情况,我们知道,取n个随机数发生器,存在n个概率相同的独立事件,我们只使用这n个事件就得到1/n的概率了。例如n=3,有8中情况000,001,010,011,100,101,110,111,其中001,010,100的概率都是p^2*(1-p)。
问题二:已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10。
解决方案:这个问题和上个问题不同的是,这里产生的序列,要变成和的形式或者其他的形式,那么概率就会发生变化了。
如果能够得到一组等概率的数,不管是什么数,只要等概率而且个数大于10,那么问题就可以解决了。
发现(rand7()-1)*7+rand7(),可以等概率的生成1到49。
呵呵,这不就得了,只要把11-49砍掉就可以了。不过这样的效率比较低。可以砍掉41-49,然后在把1-40映射到1-10(例如模10),那么问题也就解决了。
问题三:调用RANDOM(0, 1)实现RANDOM(a, b)
解决方案:这里的RANDOM(0, 1)是指等概率产生0或1,显然,RANDOM(a, b) = a + RANDOM(0, b-a)
可以这样做:
1,取 n=b-a+1,取最小的正整数m,使得 2^m >= n
2,调用RANDOM(0,1),输出m-bit位整数N ( N >= 0 and N <= 2^m-1)
3, if N >=0 and N <= b-a
then return a+N
else 重新执行步骤 2
附:
// 问题一代码实现
int MyRand() { int a = randP(), b = randP(); if(a != b) return a; return -1; }
//问题三的一种递归实现,n不是2的幂时有误差
int random( a, b ) { if( a == b ) return a; if( random( 0, 1 ) ) return random( a, (a+b)/2 ); else return random( (a+b)/2 + 1, b ); }
参考链接:
1. CSDN_geekster-一些常见的概率生成器的题目
2. CSDN_chfe910-[面试题][数学与概率]设计随机数生成器