随机数问题小结

1、利用(0,1)之间的随机数生成器rand()生成(a,b)之间的随机数:(b-a)/rand() + a;

2、利用(0,a)之间的随机数生成器rand()生成(0,b)之间的随机数:只要a和b之间没有倍数关系

3、求一个string的最长回文前缀子串:用逆序的数组作为patten,用KMP算法求最后停在哪里。 

4、假设random(0,1)输出结果是50%的0和50%的1 ,要求利用random(0,1)随机在[a,b]内产生一个数。

题目2的解答(答案来自水木精华区):

已知 
所给的随机数发生器的样本空间为 [0, M),即 [0, RAND_MAX]; 
结果的样本空间大小 N,即 divisor。 
考虑 M 进制数 D,即 dividend。 
  
   while divisor > space and error_bound > tolerant_error do 
   // divisor > space 后面说; 
   // error_bound 是误差上界,tolerant_error 是可容忍的误差, 
   // 注意 tolerant_error 可为 0,但为 0 时不能保证算法停机。 
  
     dividend = remainder * (RAND_MAX+1) + random(0, RAND_MAX) 
     // M 进制数 D 的次低位取 R(详见下文),而最低位在[0, M)上随机生成。 
     // 这里 random(0, RAND_MAX) 是原题中所给的随机数发生器。 
  
     remainder = dividend % divisor 
     // D 除以 N 的余数 R 就是所求随机数,如果不考虑误差的话。 
     // (以上误差指的是结果分布的误差,定义参见原帖) 
  
     // 考虑 D 值的样本空间[0, S),S = space * M, 
     // 这里 space 是下条语句执行前的值。 
     space = space * (RAND_MAX+1) - dividend + remainder 
     // 如果 floor(D/N+1)*N <= S,即 D 没有落在最后的“零头”上, 
     // 那么 R 在[0, N)上均匀分布的。 
     //   floor(D/N+1)*N 即 D-R+N,D-R+N <= S 即 N <= S-D+R, 
     //   而此时 space = S-D+R,这就是前面为什么 while divisor > space 
  
     // 如果 D 落在了最后的零头上,简单的办法就是重来, 
     // 但这里将“零头” R 放在下次生成的 D 的次高位,以 减少调用 
     // 随机数发生器的次数 并 控制误差。 
     // (R 可能大于 M,不过这不影响算法。) 
  
     error_bound /= (RAND_MAX+1) 
     // M 进制数 D 每多生成一位,误差上界缩小到 1/M。 
  
以上。 
  
另一个等价的做法是逐位生成 M 进制纯小数 D,如果在小数点后第 B 位上, 
存在 R 使 [D, D+1/M^B) 完全落在 [R/N, (R+1)/N) 内,那么该 R 值即所求, 
如果只是有交集,那么就是还有误差,如果该误差在容忍范围内,那么 R 即所求, 
否则就继续生成更多位。注意这里的区间是连续的。 
  
以上做法的主要目的是在可容忍误差的情况下,保证算法可在确定步数内停机。 
如果不能容忍误差,并且 N 和 M 的质因数集(非重集)不等,那么不存在有限算法, 
严格来说就是不存在正确算法。

 问题4的解答:random(0,1)每次都生成0和1,概率分别是0.5。考虑二进制数,设置n = b -a + 1, 找一个最小的m使得2^m>=n.

 int generateRandom(int a, int b){
   while(1){
   int x = 1; int n = b -a + 1;
   for(int i = 0; i < m; i++){
        x = x & random();
        x >> 1;
    }
    if ( x >= 0 && x <= n){
         return x + a;
    }
    } 
 }

 

posted @ 2013-03-07 14:56  一只会思考的猪  阅读(294)  评论(0编辑  收藏  举报