在写抽奖程序的时候碰到的一个问题:
1.在不预知组内成员的情况下(也不将数个中奖位置预读在内存中)保证每m个元素中总能抽中n个;
2.保证同等价值的元素抽取概率君相等为n‘/m;
3.n可分为n1,n2……;
选取的算法放弃经典概率的随机数生成,而改用条件概率;
1.首先判断第b/m位置的元素是否是a/n选取的特殊元素;P=(n-a)/(m-b+1);
2.进一步在a/n的基础上判断c/n’是否特殊;P=(n‘-c)/(n-a+1);
3.将2迭代在1的结果中判断;
4.若n'还可再分,重复2步骤;
实例代码如下
package full.hit;
public class fullhit {
public static int geted = 0;
public static boolean task = false;
public static int[] a = new int[21];
public static int[] b = new int[21];
public static int[] c = new int[21];
boolean first_hit(int round) {
boolean tempmark;
tempmark = false;
int rate = 0;
int fate = 0;
rate = (int) ((4 - geted) * 10000 / (20 - round + 1));
fate = (int) (10000 * Math.random() + 1);
if (fate <= rate) {
tempmark = true;
geted++;
}
return tempmark;
}
int socend_hit() {
int r;
int f;
int tempint = 0;
r = (int) 10000 / (4 - geted + 1);
f = (int) (10000 * Math.random());
if ((task == false) & (f <= r)) {
tempint = 1;
task = true;
} else {
tempint = 0;
}
return tempint;
}
public static void main(String[] args) {
int round = 0;
int s = 0;// 模拟楼层计数器
int ta = 0;// 一等奖检测
int tb = 0;// 二等奖检测
boolean mark;// 检测:不符合每20个出现1个一等奖和3个二等奖就终止程序
fullhit fh = new fullhit();
for (int i = 1; i <= 10000000; i++) {// 模拟10mX20个楼层
round = 0;
geted = 0;
task = false;
ta = 0;
tb = 0;
mark = true;
while (round < 20) {
round++;
if (fh.first_hit(round)) {
if (fh.socend_hit() == 1) {
// 模拟一等奖;
a[round]++;
ta++;
//省略处理一等奖的方法;
} else {
// 模拟二等奖;
b[round]++;
tb++;
//同上
}
} else {
// 模拟三等奖;
c[round]++;
同上
}
}
if (ta != 1) {
mark = false;
}
if (tb != 3) {
mark = false;
}
if (mark == false) {
System.out.println("error");
break;
}
}
for (int i = 1; i <= 20; i++) {
// 查看选中概率
System.out.print("a" + i + "的个数=" + a[i] + "(" + a[i] / 10000
+ "%。)|");
System.out.print("b" + i + "的个数=" + b[i] + "(" + b[i] / 10000
+ "%。)|");
System.out.print("c" + i + "的个数=" + c[i] + "(" + c[i] / 10000
+ "%。)");
System.out.println("|");
s = a[i] + b[i] + c[i];
}
System.out.println(s);
}
}
运行结果
a1的个数=499824(49%。)|b1的个数=1497290(149%。)|c1的个数=8002886(800%。)|
a2的个数=500605(50%。)|b2的个数=1498930(149%。)|c2的个数=8000465(800%。)|
a3的个数=500648(50%。)|b3的个数=1498506(149%。)|c3的个数=8000846(800%。)|
a4的个数=498906(49%。)|b4的个数=1499513(149%。)|c4的个数=8001581(800%。)|
a5的个数=499420(49%。)|b5的个数=1501569(150%。)|c5的个数=7999011(799%。)|
a6的个数=499057(49%。)|b6的个数=1499303(149%。)|c6的个数=8001640(800%。)|
a7的个数=499637(49%。)|b7的个数=1500461(150%。)|c7的个数=7999902(799%。)|
a8的个数=499751(49%。)|b8的个数=1497757(149%。)|c8的个数=8002492(800%。)|
a9的个数=499362(49%。)|b9的个数=1500223(150%。)|c9的个数=8000415(800%。)|
a10的个数=500398(50%。)|b10的个数=1501744(150%。)|c10的个数=7997858(799%。)|
a11的个数=500780(50%。)|b11的个数=1499652(149%。)|c11的个数=7999568(799%。)|
a12的个数=501419(50%。)|b12的个数=1500825(150%。)|c12的个数=7997756(799%。)|
a13的个数=499531(49%。)|b13的个数=1498670(149%。)|c13的个数=8001799(800%。)|
a14的个数=500125(50%。)|b14的个数=1499623(149%。)|c14的个数=8000252(800%。)|
a15的个数=499369(49%。)|b15的个数=1500529(150%。)|c15的个数=8000102(800%。)|
a16的个数=500528(50%。)|b16的个数=1499332(149%。)|c16的个数=8000140(800%。)|
a17的个数=500256(50%。)|b17的个数=1501182(150%。)|c17的个数=7998562(799%。)|
a18的个数=500026(50%。)|b18的个数=1500794(150%。)|c18的个数=7999180(799%。)|
a19的个数=500726(50%。)|b19的个数=1501076(150%。)|c19的个数=7998198(799%。)|
a20的个数=499632(49%。)|b20的个数=1503021(150%。)|c20的个数=7997347(799%。)|
10000000
可以看到a的概率在5%,b的概率在15%,c的概率在80%;同时mark没有因为每组中产生特殊元素不够而break;选取方式为单次产生随机,每次结果直接利用后消灭内存;符合开始的设定!