抽牌概率
2017-01-05 16:50
411 查看
本节探讨两例:有趣的抽牌概率计算,其中单色的数字牌设计比较简单,而由多花色扑克组成的数字牌涉及编码的转换,其中设计较为复杂,也更具有吸引力;
涉及到概率计算,必须统计事件的总体数与满足指定条件事件的个数,这是概率计算的基础;
在这n张数字牌中同时抽取3张,记3张牌上的整数之和为素数的概率为p(n);
输入n(n>=10),计算并输出概率p(n)(精确到小数点后3位);
1.说明:
因任3张牌整数之和不小于6,可以排除唯一偶素数“2”;
(1)、试商法判别素数;
判别一个大于1的奇数i是否为素数,最简单的是根据素数的定义应用试商法完成,即用奇数(3~sqrt(i))进行试商判别;
为方便素数检测,设置数组q[i],对3n以内的整数i通过试商法给q[i]赋值:若i为素数,q[i]=1;否则q[i]=0;
(2)、枚举循环设计;
注意到任取3张牌即所得3个数不能相同。因而设置的i,j,k三重枚举循环的取值范围分别为:i(1~n-2),j(i+1~n-1),k(j+1~n);
这样的枚举循环设置,确保每不同的三张一组抽取,既无遗漏,也没有重复,这一点很重要,如果枚举循环设置不精准,出现遗漏或重复,会直接导致统计结果错误;
设s为从n张中取3张的总数,显然有:
s=(3)C(n)=(n(n-1)(n-2))/6;
在内循环中通过w++统计所有不同的抽牌次数,并对取得的3个数应用q[i+j+k]=1判定3个数之和是否为素数,若是素数则通过m++统计和为素数的抽取次数;
(3)、计算概率;
循环结束后,比较w与s,若w!=s,说明循环设置出错,退出程序;
只有当w=s时,才计算并输出概率值p=m/w;
2.程序设计:
3.程序运行示例及其注意事项:
注意:通过三重循环枚举实现3张抽牌是可行的,也是可靠的,由s与w是否相等的检测可知枚举既无重复,也不存在遗漏;
试在扑克牌每一花色的数码靠前的n(2<=n<=13)张牌(即每种花色的数码均为1,2,……,n)组成的4n张牌中抽取3张,3张牌上的数码之和为素数的概率记为p(n);
输入n,计算并输出p(n)(精确到小数点后3位);
1.说明:
在扑克牌的4种花色牌中抽取要比前面单一数字牌抽取复杂,涉及到牌上的原数码与抽取编码之间的转换;
(1)、抽取编号;
为实现在4n张牌中每不同的3张都能抽到,把4n张牌进行抽取编号:
任取一种花色其n张牌按顺序抽取编号为1~n(此时抽取编号与牌上数码相同);
第2种花色的n张牌按顺序抽取编号为n+1~2n(即数码为1的编号为n+1,数码为2的编号为n+2,……,类推);
第3种花色的n张牌按顺序抽取编号为2n+1~3n;
最后第4种花色的n张牌按顺序抽取编号为3n+1~4n;
(2)、设置素数检测数组;
为方便素数检测,设置数组q[i],对4n以内的整数i通过试商法给q[i]赋值:若i为素数,q[i]=1;否则q[i]=0;
(3)、枚举循环设计;
为实现在4n张牌中任取3张牌,设置i,j,k三重枚举循环,其取值范围分别为:i(1~4n-2),j(i+1~4n-1),k(j+1~4n);
这样的枚举循环设置,确保每不同的三张一组抽取,既无遗漏,也没有重复;
(4)、抽取次数的总数;
设s为从4n张中抽取3张的总数,显然有:
s = (3)C(4n) = (4n(4n-1)(4n-2))/6
在i,j,k三重枚举循环内通过w++统计所有不同的抽取次数,循环结束后,比较w与s,若w!=s,说明循环设置出错,退出程序;
(5)、恢复牌上的原数码;
以上循环中的i,j,k是抽取编号,把这些抽取编号转换为扑克牌的原数码(设置为i1、j1、k1)是必要的,也是设计的关键所在;
若i>n:i1=i%n,此时若i1=0,则i1=n;
例如,若n=13时,抽取编号i=39,根据抽取编号的设置可知该牌的原数码应是21%13,该牌的原数码为8;
若n=13时,抽取编号i=39,根据抽取编号的设置可知该牌的原数码应是13,而由求余运算39%13=0,因此把0转换为13是必要的;
抽取编号j,k的转换与上面类似;
(6)、判别与计算;
应用q[i1+j1+k1]=1判定抽取的3张牌的数字之和为素数,并通过m++统计所要求的“和为素数”的抽取次数;
最后计算并输出概率值p=m/w;
2.程序设计:
3.程序运行示例及其注意事项:
注意:以上程序设计的重点也是难点是把抽取编号i、j、k转换为牌的原数码i1、j1、k1,这也是该设计的灵巧之处;
有4种数字牌,其张数分别为a张,编号为1~a;b张,编号为1~b;c张,编号为1~c;d张,编号为1~d;
试在这4种数字牌共s=a+b+c+d张牌中抽取3张,试求3张牌上的数码之和为素数的概率p;
输入整数a,b,c,d(1~a,b,c,d<=100),计算并输出概率p(精确到小数点后3位);
1.说明:
(1)、抽取编号;
为实现在s=a+b+c+d张牌中每不同的3张都能抽到,把s张牌进行抽取编号:
取第1种花色其a张牌按顺序抽取编号为1~a(此时抽取编号与牌上数码相同);
第2种花色的b张牌按顺序抽取编号为a+1~a+b(即数码为1的编号为a+1,数码为2的编号为a+2,……,类推);
第3种花色的c张牌按顺序抽取编号为a+b+1~a+b+c;
最后第4种花色的d张牌按顺序抽取编号为a+b+c+1~a+b+c+d;
(2)、设置素数检测数组;
为方便素数检测,设置数组q[i],对s以内的整数i通过试商法给q[i]赋值:
若i为素数,q[i]=1;否则q[i]=0;
(3)、枚举循环设计;
为实现在s张牌中任取3张牌,设置i,j,k三重枚举循环,其取值范围分别为:i(1~s-2),j(i+1~s-1),k(j+1~s);
这样的枚举循环设置,确保每不同的三张一组抽取,即无遗漏,也没有重复;
(4)、抽取次数的总数;
从s张中抽取3张的总数,显然有:
(3)C(s) = (s(s-1)(s-2))/6
在i,j,k三重美剧循环内通过w++统计所有不同的抽取次数,循环结束后,比较w与上式计算的总数是否相等,若不等,说明循环设置出错,退出程序;
(5)、恢复牌上的原数码;
以上循环中的i、j、k是抽取编号,把这些抽取编号转换为各色牌的原数码(设置为i1、j1、k1)是必要的,也是设计的关键所在;
设置把抽取编号x(即i、j、k)转换为原数码y(即i1、j1、k1)的转换函数tr():
若x<=a,则y=x;
若a< x且x<=a+b,则y=x-a;
若a+b< x且x<=a+b+c,则y=x-a-b;
若a+b+c< x且x<=a+b+c+d,则y=x-a-b-c;
(6)、判别与计算;
应用q[i1+j1+k1]=1判定抽取的3张牌的数字之和为素数,并通过m++统计所要求的“和为素数”的抽取次数;
最后计算并输出概率值p=m/w;
2.程序设计:
3.程序运行示例及其注意事项:
若输入a=b=c=d=13,结果即为“抽扑克牌”的运行结果;
进一步把4色拓广为一般m色,有兴趣的读者请自行探讨;
涉及到概率计算,必须统计事件的总体数与满足指定条件事件的个数,这是概率计算的基础;
抽数字牌
有n张数字牌,数字牌上分别标有整数1,2,3,……,n;在这n张数字牌中同时抽取3张,记3张牌上的整数之和为素数的概率为p(n);
输入n(n>=10),计算并输出概率p(n)(精确到小数点后3位);
1.说明:
因任3张牌整数之和不小于6,可以排除唯一偶素数“2”;
(1)、试商法判别素数;
判别一个大于1的奇数i是否为素数,最简单的是根据素数的定义应用试商法完成,即用奇数(3~sqrt(i))进行试商判别;
为方便素数检测,设置数组q[i],对3n以内的整数i通过试商法给q[i]赋值:若i为素数,q[i]=1;否则q[i]=0;
(2)、枚举循环设计;
注意到任取3张牌即所得3个数不能相同。因而设置的i,j,k三重枚举循环的取值范围分别为:i(1~n-2),j(i+1~n-1),k(j+1~n);
这样的枚举循环设置,确保每不同的三张一组抽取,既无遗漏,也没有重复,这一点很重要,如果枚举循环设置不精准,出现遗漏或重复,会直接导致统计结果错误;
设s为从n张中取3张的总数,显然有:
s=(3)C(n)=(n(n-1)(n-2))/6;
在内循环中通过w++统计所有不同的抽牌次数,并对取得的3个数应用q[i+j+k]=1判定3个数之和是否为素数,若是素数则通过m++统计和为素数的抽取次数;
(3)、计算概率;
循环结束后,比较w与s,若w!=s,说明循环设置出错,退出程序;
只有当w=s时,才计算并输出概率值p=m/w;
2.程序设计:
#include<stdio.h> #include<math.h> int main() { int i,j,k,n,t,z,q[3000]; long m,s,w; double p; printf("请输入牌的张数n(n<1000):"); scanf("%d",&n); for(i=1;i<=3*n;i++) q[i]=0; for(i=3;i<=3*n;i=i+2) { t=1; z=(int)sqrt(i); for(j=3;j<=z;j=j+2) if(i%j==0) { t=0; break; } if(t==1) /*奇数i为素数时标记q[i]=1*/ q[i]=1; } m=w=0; for(i=1;i<=n-2;i++) /*三重循环枚举抽牌*/ for(j=i+1;j<=n-1;j++) for(k=j+1;k<=n;k++) { w++; if(q[i+j+k]==1) m++; /*统计和为素数的数目*/ } s=n*(n-1)*(n-2)/6; if(s!=w) { printf("统计出现问题!"); return; } p=(double)m/w; printf("在%d张牌取3张不同取法%ld次,和为素数的%ld次\n",n,w,m); printf("和为素数的概率为%.03f\n",p); }
3.程序运行示例及其注意事项:
请输入牌的张数n(n<1000):100 在100张牌取3张不同取法161700次,和为素数的30791次 和为素数的概率为0.190
注意:通过三重循环枚举实现3张抽牌是可行的,也是可靠的,由s与w是否相等的检测可知枚举既无重复,也不存在遗漏;
抽扑克牌
玩扑克牌是最普及也是最流行的娱乐活动,扑克牌除大小王之外有红心、方片、草花、黑桃4种花色,每一种花色有A,2,……,10,J,Q,K(约定A为数码1,J,Q,K分别为数码11、12、13)共13个数码;试在扑克牌每一花色的数码靠前的n(2<=n<=13)张牌(即每种花色的数码均为1,2,……,n)组成的4n张牌中抽取3张,3张牌上的数码之和为素数的概率记为p(n);
输入n,计算并输出p(n)(精确到小数点后3位);
1.说明:
在扑克牌的4种花色牌中抽取要比前面单一数字牌抽取复杂,涉及到牌上的原数码与抽取编码之间的转换;
(1)、抽取编号;
为实现在4n张牌中每不同的3张都能抽到,把4n张牌进行抽取编号:
任取一种花色其n张牌按顺序抽取编号为1~n(此时抽取编号与牌上数码相同);
第2种花色的n张牌按顺序抽取编号为n+1~2n(即数码为1的编号为n+1,数码为2的编号为n+2,……,类推);
第3种花色的n张牌按顺序抽取编号为2n+1~3n;
最后第4种花色的n张牌按顺序抽取编号为3n+1~4n;
(2)、设置素数检测数组;
为方便素数检测,设置数组q[i],对4n以内的整数i通过试商法给q[i]赋值:若i为素数,q[i]=1;否则q[i]=0;
(3)、枚举循环设计;
为实现在4n张牌中任取3张牌,设置i,j,k三重枚举循环,其取值范围分别为:i(1~4n-2),j(i+1~4n-1),k(j+1~4n);
这样的枚举循环设置,确保每不同的三张一组抽取,既无遗漏,也没有重复;
(4)、抽取次数的总数;
设s为从4n张中抽取3张的总数,显然有:
s = (3)C(4n) = (4n(4n-1)(4n-2))/6
在i,j,k三重枚举循环内通过w++统计所有不同的抽取次数,循环结束后,比较w与s,若w!=s,说明循环设置出错,退出程序;
(5)、恢复牌上的原数码;
以上循环中的i,j,k是抽取编号,把这些抽取编号转换为扑克牌的原数码(设置为i1、j1、k1)是必要的,也是设计的关键所在;
若i>n:i1=i%n,此时若i1=0,则i1=n;
例如,若n=13时,抽取编号i=39,根据抽取编号的设置可知该牌的原数码应是21%13,该牌的原数码为8;
若n=13时,抽取编号i=39,根据抽取编号的设置可知该牌的原数码应是13,而由求余运算39%13=0,因此把0转换为13是必要的;
抽取编号j,k的转换与上面类似;
(6)、判别与计算;
应用q[i1+j1+k1]=1判定抽取的3张牌的数字之和为素数,并通过m++统计所要求的“和为素数”的抽取次数;
最后计算并输出概率值p=m/w;
2.程序设计:
#include<stdio.h> #include<math.h> int main() { int i,j,k,i1,j1,k1,n,t,z,q[3000]; long m,s,w; double p; printf("请输入每色牌的张数n(2<=n<=13):"); scanf("%d",&n); for(i=1;i<=3*n;i++) q[i]=0; for(i=3;i<=3*n;i=i+2) { t=1; z=(int)sqrt(i); for(j=3;j<=z;j=j+2) if(i%j==0) { t=0; break; } if(t==1) q[i]=1; /*i为素数时标记q[i]=1*/ } m=w=0; 4000 for(i=1;i<=4*n-2;i++) /*三重循环枚举抽3张牌*/ for(j=j+1;j<=4*n-1;j++) for(k=j+1;k<=4*n;k++) { w++; i1=i%n; j1=j%n; k1=k%n; if(i1==0) i1=n; /*恢复扑克上的原数码*/ if(j1==0) j1=n; if(1==0) k1=n; if(q[i1+j1+k1]==1) m++; /*统计和为素数的数目*/ } s=4*n*(4*n-1)*(4*n-2)/6; /*s为从4n张中取3张的总数*/ if(s!=w) { printf("统计出现问题!"); return; } p=(double)m/w; printf("在扑克每色%d张牌中抽取3张有不同取法%ld次,\n",n,w); printf("其中和为素数的取法%ld次;和为素数的概率为%.3f\n",m,p); }
3.程序运行示例及其注意事项:
请输入每色牌的张数n(2<=n<=13):13 统计出现问题!在扑克每色13张牌中抽取3张有不同取法22100次, 其中和为素数的取法6068次;和为素数的概率为0.275
注意:以上程序设计的重点也是难点是把抽取编号i、j、k转换为牌的原数码i1、j1、k1,这也是该设计的灵巧之处;
拓广抽扑克牌
上面扑克牌各色牌的张数相同,拓广到4色数字牌的张数任意指定;有4种数字牌,其张数分别为a张,编号为1~a;b张,编号为1~b;c张,编号为1~c;d张,编号为1~d;
试在这4种数字牌共s=a+b+c+d张牌中抽取3张,试求3张牌上的数码之和为素数的概率p;
输入整数a,b,c,d(1~a,b,c,d<=100),计算并输出概率p(精确到小数点后3位);
1.说明:
(1)、抽取编号;
为实现在s=a+b+c+d张牌中每不同的3张都能抽到,把s张牌进行抽取编号:
取第1种花色其a张牌按顺序抽取编号为1~a(此时抽取编号与牌上数码相同);
第2种花色的b张牌按顺序抽取编号为a+1~a+b(即数码为1的编号为a+1,数码为2的编号为a+2,……,类推);
第3种花色的c张牌按顺序抽取编号为a+b+1~a+b+c;
最后第4种花色的d张牌按顺序抽取编号为a+b+c+1~a+b+c+d;
(2)、设置素数检测数组;
为方便素数检测,设置数组q[i],对s以内的整数i通过试商法给q[i]赋值:
若i为素数,q[i]=1;否则q[i]=0;
(3)、枚举循环设计;
为实现在s张牌中任取3张牌,设置i,j,k三重枚举循环,其取值范围分别为:i(1~s-2),j(i+1~s-1),k(j+1~s);
这样的枚举循环设置,确保每不同的三张一组抽取,即无遗漏,也没有重复;
(4)、抽取次数的总数;
从s张中抽取3张的总数,显然有:
(3)C(s) = (s(s-1)(s-2))/6
在i,j,k三重美剧循环内通过w++统计所有不同的抽取次数,循环结束后,比较w与上式计算的总数是否相等,若不等,说明循环设置出错,退出程序;
(5)、恢复牌上的原数码;
以上循环中的i、j、k是抽取编号,把这些抽取编号转换为各色牌的原数码(设置为i1、j1、k1)是必要的,也是设计的关键所在;
设置把抽取编号x(即i、j、k)转换为原数码y(即i1、j1、k1)的转换函数tr():
若x<=a,则y=x;
若a< x且x<=a+b,则y=x-a;
若a+b< x且x<=a+b+c,则y=x-a-b;
若a+b+c< x且x<=a+b+c+d,则y=x-a-b-c;
(6)、判别与计算;
应用q[i1+j1+k1]=1判定抽取的3张牌的数字之和为素数,并通过m++统计所要求的“和为素数”的抽取次数;
最后计算并输出概率值p=m/w;
2.程序设计:
#include<stdio.h> #include<math.h> int a,b,c,d,x,y; int main() { int i,j,k,i1,j1,k1,s,t,z,q[400]; long m,w; double p; int tr(); printf("请输入每色牌的张数a,b,c,d(1<a,b,c,d<=100):"); scanf("%d,%d,%d,%d",&a,&b,&c,&d); s=a+b+c+d; for(i=1;i<=s;i++) q[i]=0; for(i=3;i<=s;i=i+2) { t=1; z=(int)sqrt(i); for(j=3;j<=z;j=j+2) if(i%j==0) { t=0; break; } if(t==1) q[i]=1; /*i为素数时标记q[i]=1*/ } m=w=0; for(i=1;i<=s-2;i++) /*三重循环枚举抽3张牌*/ for(j=i+1;j<=s-1;j++) for(k=j+1;k<=s;k++) { w++; /*w为从s张中取3张的总数*/ x=i; tr(); i1=y; x=j; tr(); /*恢复牌上的原数码*/ j1=y; x=k; tr(); k1=y; if(q[i1+j1+k1]==1) m++; /*统计和为素数的数目*/ } if(w!=s*(s-1)*(s-2)/6) { printf("统计出现问题!"); return; } p=(double)m/w; printf("在4色共%d张牌中抽取3张有不同取法%ld次,\n",s,w); printf("其中和为素数的取法%ld次;和为素数的概率为%.3f\n",m,p); } int tr() /*抽取编号x转换为原数码y的转换函数*/ { if(x<=a) y=x; else if(a<x && x<=a+b) y=x-a; else if(a+b<x && x<=a+b+c) y=x-a-b; else y=x-a-b-c; return y; }
3.程序运行示例及其注意事项:
请输入每色牌的张数a,b,c,d(1<a,b,c,d<=100):10,20,40,50 在4色共120张牌中抽取3张有不同取法280840次, 其中和为素数的取法64599次;和为素数的概率为0.230
若输入a=b=c=d=13,结果即为“抽扑克牌”的运行结果;
进一步把4色拓广为一般m色,有兴趣的读者请自行探讨;
相关文章推荐
- Rabin-Miller概率素数检验算法
- 常见概率分布及在R中的应用
- ZOJ 3329 One Person Game(概率问题)
- [HDU 5816] Hearthstone (概率DP+状压)
- 概率与统计的区别
- LightOj 1265 - Island of Survival(概率)
- 利用 p, 1-p 随机数发生器知道等概率发生器
- LightOJ 1104 Birthday Paradox (离散概率)
- 等概率获取随机数
- POJ 2096 (概率dp)
- 百家乐大小概率
- hdu5001 Walk (概率dp)
- 【ZZ】蓄水池发求等概率的从N个元素中选取出K个元素
- 【BZOJ3566】概率充电器,树形概率DP
- 最大概率选择到“最好女孩”的算法
- LightOJ 1317 (据说是概率DP的...水题)
- hdu 4405 Aeroplane chess 概率dp
- codeforces 711E E. ZS and The Birthday Paradox(数学+概率)
- Java算法 概率算法(蒙特卡洛概率算法求圆周率)
- 剑指Offer43 n个骰子点数概率