例子是引用重点在注意事项
举个例子,有三个武将A、B、C,他们的出现机率分别是30%、40%和30%。首先产生一个随机数,这里的权重总和是100,分为三个区间,1~30,31~70,71~100。自然随机数的范围也在100以内。假如这个随机数是49,很明显49是在31~70这个区间内,那么可确定该次随机产生的武将是B。思路是这样,但是怎么用算法去实现呢?
传入一个二维数组 in[序号][权重]
根据不同序号的权重来获取序号
/**
* 根据权重获取序号
*
* @param weights
* @return
*/
public static int RandomByWeight(int[][] weights) {
Random random = new Random();
int weightSum = 0;
for (int i = 0; i < weights.length; i++) {
weightSum += weights[i][1]*10000;//注意这一步至关重要 10000是精度 这个值越大精度越高 这里取10的倍数 因为比例不变
}
//总的权重中生成一个随机数
int number_rand = random.nextInt(weightSum);
int sum_temp = 0;
//循环数组 判断生成的随机数是否小于等于当前权重是就返回序号 否则加上当前的权重继续循环
for (int i = 0; i < weights.length; i++) {
sum_temp += weights[i][1]*10000;
if (number_rand <= sum_temp) {
return weights[i][0];
}
}
return -1;
}
注意事项:
我在网上找了很多资料最终修改成上面的代码 其中weightSum += weights[i][1]*10000;这句话的意思其实是为了扩大精度。
我们下面举个例子说明;
有序号a,b,c三个序号, 权重分别为1,2,1; 如果权重只是按照1,2,1去计算。那么c永远不会有出现的机会,但是如果权重按照10000,20000,10000去计算则他们的比例趋近于1:2:1,这是因为random.nextInt(权重和)生成的随机数范围越大越精确 当权重和为4的时候与权重和为4000的时候明显不一样。
关于权重为1,2,1 不会出现c的原因是由于random.nextInt(4)生成的随机数是0,1,2,3 ;3和4之间不会生成其他随机数所以不会有c ,但是random.nextInt(40000)生成的随机数30000和40000之间可以生成随机数这部分的随机数可以生成c;
如果你还是看不明白只需要记得在用上面的这种思路去获取随机数的时候一定要讲权重值扩大。