随机数问题

来源:互联网 发布:疯狂的美工好不好 编辑:程序博客网 时间:2024/05/20 23:06

一、用随机函数构造另一个随机函数

比如,有这样一个需求,现在有一个rand5()函数,这个函数可以生成1-5的随机数,让你通过这个函数生成1-7范围的随机数。

怎么做了?

一般思路是这样的:用两次rang5函数,通过这两次rand5结果,构造出一个随机数范围包括0-7,但比0-7大的范围就好了。比如(rand5 -1)*5 +rand5,它的范围为1-25(包括0-7),因为rand5产生每个数随机概率相等,那么(rand5 -1)*5 +rand5产生的每个数的概率也是相等的。我们只要1-7的数,因此代码可以这样写:

int rand5()  {      int n =1 + rand()%5;      return n;  }  int rand7(){    int n=0;    while((n=((rand5 -1*5 +rand5))>7);    return n;}

对于上述代码,可能要循环好多次才能得到小于7的数,那么是否可以减少生成次数。可以用模来减少生成次数,因为只要是7的倍数范围,模后每个数的概率是相等的,那么上述代码可以改为:

int rand7(){    int n=0;    while((n=((rand5 -1*5 +rand5))>21);    return n%7;}

二、洗牌算法

1、全局洗牌:

a)首先生成一个数组,大小为54,初始化为1~54b)按照索引1到54,逐步对每一张索引牌进行洗牌,随机生成一个54以内的随机数,那么我们的索引牌就和这个余数牌进行交换处理c)等多索引到54结束后,一副牌就洗好了
void Shuffle(vector<int> card)  {      for(int i=0;i<card.size();i++)      {          swap(num[i], num[rand()%(card.size())]);      }  }  

2、局部洗牌法:

上面的算法有一个问题,我们发现每次洗牌之后原来洗好的牌都会进行二次操作,所以不妨加以改进:
a)同样,首先我们生成一个大小为54的数组,数组排列为1~54
b)索引牌从1开始,到54结束。这一次索引牌只和剩下还没有洗的牌进行交换, index= i+ rand() %(size - i)
c)等到所有的索引牌都洗好之后,一副牌就弄好了

void Shuffle(vector<int> card)  {      for(int i=0;i<card.size();i++)      {          swap(num[i], num[ i+ rand() %(card.size()- i)]);      }  }  

参考:
一步一步写算法(之洗牌算法)
给定一个随机函数,求另外一个随机函数

0 0