假设剩余红包金额为m元,剩余人数为n,那么有如下公式。
每次抢到的金额 = 随机区间 [0.01,m /n × 2 - 0.01]元 这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺 序而造成不公平。
举个例子如下。 假设有5个人,红包总额100元。 100÷5×2 = 40,所以第1个人抢到的金额随机范围是[0.01,39.99]元,在正常 情况下,平均可以抢到20元。 假设第1个人随机抢到了20元,那么剩余金额是80元。 80÷4×2 = 40,所以第2个人抢到的金额的随机范围同样是[0.01,39.99]元,在 正常的情况下,还是平均可以抢到20元。 假设第2个人随机抢到了20元,那么剩余金额是60元。 60÷3×2 = 40,所以第3个人抢到的金额的随机范围同样是[0.01,39.99]元,平 均可以抢到20元。 以此类推,每一次抢到金额随机范围的均值是相等的。 这样做真的是均等的吗?如果第1个人运气很好,随机 抢到39元,第2个人所抢金额的随机区间不就缩减到[0.01,60.99]元了吗? 这个问题提得很好。第1次随机的金额有一半概率超过20 元,使得后面的随机金额上限不足39.99元;但相应地,第1次随机的金额同 样也有一半的概率小于20元,使得后面的随机金额上限超过39.99元。因此从 整体来看,第2次随机的平均范围仍然是[0.01,39.99]元。
/** * @program: demo * @Description: 抢红包工具类 * @Author: zwx * @Date: 2021/7/19 16:34 */ public class RedEnvelopeUtils { /** * 抢红包 * @method: divideRedPackage * @param totalAmount 总金额,以分为单位 * @param totalPeopleNum 总人数 * @return {@link List< Integer> } * @Author: zwx * @Date: 2021/7/19 16:36 */ public static List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum){ List<Integer> amountList = new ArrayList<Integer>(); Integer restAmount = totalAmount; Integer restPeopleNum = totalPeopleNum; Random random = new Random(); for(int i=0; i<totalPeopleNum-1; i++){ //随机范围:[1,剩余人均金额的2倍-1] 分 int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1; restAmount -= amount; restPeopleNum --; amountList.add(amount); } amountList.add(restAmount); return amountList; } public static void main(String[] args) { //模拟20个人抢100元 List<Integer> accountList = divideRedPackage(10000, 20); for (Integer account : accountList) { System.out.println("抢到的金额:"+new BigDecimal(account).divide(new BigDecimal(100))); } } }
20个人抢100,打印结果为:
抢到的金额:2.77
抢到的金额:5.28
抢到的金额:5.07
抢到的金额:2.18
抢到的金额:9.87
抢到的金额:8.62
抢到的金额:8.63
抢到的金额:0.41
抢到的金额:7.92
抢到的金额:8.17
抢到的金额:3.06
抢到的金额:0.87
抢到的金额:1.09
抢到的金额:5.49
抢到的金额:6.4
抢到的金额:1.43
抢到的金额:8.38
抢到的金额:6
抢到的金额:6.03
抢到的金额:2.33