给定能随机生成1到5的函数,写出能随机生成1到7的函数
算法实现:拒绝采样法,生成目标范围的随机数,即生成满足题目要求的样本空间,5<7<5*5,只需两次调用rand_5(),可产生25个样本空间分别和1--25个正整数一一映射,为了保证等概率,22,23,24,25舍去;如图所示:1--7中的每个数在样本空间出现的概率为3/25, 所以它们等概率出现的概率就为1/7了,如图所示,算法实现如下:
1 2 3 4 5
1 1 2 3 4 5
2 6 7 1 2 3
3 4 5 6 7 1
4 2 3 4 5 6
5 7 * * * *
代码如下:
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int rand_5()
{
return rand()%5+1;
}
int rand_7()
{
int row,col,idx;
do
{
row=rand_5();
col=rand_5();
idx=col+(row-1)*5;
}while(idx>21);
return 1+(idx-1)%7;
}
int main()
{
int T;
srand((unsigned)time(NULL));
cin>>T;
while(T--)
{
cout<<rand_7()<<endl;
}
return 0;
}
发散一下 :给定能随机生成1到5的函数rand_5(),随机生成1到1000的函数rand_1000(),显然5^4=625<1000<5^5=3125, 可以5次调用rand_5(),生成1--3125个正整数,取1--3000,将3001--3125舍去;可保证1--1000每个数出现的概率为1/1000.
更一般的:给定能随机生成1到m的函数rand_m(),随机生成1到n的函数rand_n(), 其中(m<n) .
算法实现:1...求正整数k,使 m^(k-1)<n<=m^k;
2... k次调用rand_m(),输出k位m进制数N;
3...if(1<=N<=n*(m^k/n)) return 1+(N-1)%n; ...else 重新执行2...
代码如下:
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
//产生1-m的随机数
int rand_m(int m)
{
return rand()%m+1;
}
//确定k值
int BitNum(int n,int m)
{
int k=0,p=1;
while(p<n)
{
++k;
p*=m;
}
return k;
}
//产生1-n的随机数
int rand_n(int n,int m)
{
int N,cnt,s=1,i;
cnt=BitNum(n,m);
//求m^k
for(i=1;i<=cnt;i++)
s*=m;
while(true)
{
N=0;
for(i=1;i<=cnt;i++)
{
N=N*m+rand_m(m)-1;
}
N=N+1;
if(N>=1&&N<=n*(s/n))
return 1+(N-1)%n;
else continue;
}
}
int main()
{
int T,n,m,i;
srand((unsigned)time(NULL));
cin>>T;
while(T--)
{
cin>>n>>m;
for(i=1;i<=10;i++)
cout<<rand_n(n,m)<<" ";
cout<<endl;
}
return 0;
}
浙公网安备 33010602011771号