【实用算法】 红包分配 --- 二倍均值法
二倍均值法
剩余红包金额为M,剩余人数为N,那么有如下公式:
每次抢到的金额 = 随机区间 (0, M / N X 2)
这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平。
案例
假设有10个人,红包总额30元。
30/10X2 = 6, 所以第一个人的随机范围是(0,6 ),平均可以抢到 3元。
假设第一个人随机到3元,那么剩余金额是30-3 = 27 元。
27/9X2 = 6, 所以第二个人的随机范围同样是(0,6 ),平均可以抢到3元。
假设第二个人随机到3元,那么剩余金额是27-3 = 24元。
24/8X2 = 6, 所以第三个人的随机范围同样是(0,6 ),平均可以抢到3元。
假设第三个人随机到3元,那么剩余金额是24-3 = 21元。
21/7X2 = 6, 所以第三个人的随机范围同样是(0,6 ),平均可以抢到3元。
假设第四个人随机到3元,那么剩余金额是21-3 = 18元。
以此类推,每一次随机范围的均值是相等的。
代码实现
/** * * 抢红包 分配 ---- 二倍均值法实现 * @param totalAmount 总金额 * @param totalPeopleNum 总个数 * @return */ // 发红包算法,金额参数以分为单位 public static List<String> divideRedPackage(String totalAmount, Integer totalPeopleNum) { List<String> amountList = new ArrayList<>(); Integer restAmount ; boolean flag = false; boolean numeric = isNumeric(totalAmount); if (numeric){ BigDecimal multiply = new BigDecimal(totalAmount).multiply(new BigDecimal(100)); restAmount = multiply.intValue(); flag = true; }else { restAmount = Integer.parseInt(totalAmount); } Integer restPeopleNum = totalPeopleNum; Random random = new Random(); for (int i = 0; i < totalPeopleNum - 1; i++) { // 随机范围:[1,剩余人均金额的两倍),左闭右开 int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1; // 金额递减 restAmount -= amount; // 红包数量递减 restPeopleNum--; amountList.add(bigDecimalToString(flag,amount)); } //最后一个拿剩余全部 amountList.add(bigDecimalToString(flag,restAmount)); return amountList; } /** * 判断是否为小数 * @param str * @return */ private static boolean isNumeric(String str){ String[] split = str.split("\."); if (split.length > 1 && new BigDecimal(split[1]).compareTo(new BigDecimal("0")) ==1){ return true; } if (split.length > 1 && new BigDecimal(split[1]).compareTo(new BigDecimal("0")) <=0){ return false; } return false; } /** * 格式化输出 * @param flag * @param b * @return */ private static String bigDecimalToString( boolean flag,Integer b){ BigDecimal bigDecimal ; if(flag){ bigDecimal = new BigDecimal(b).divide(new BigDecimal(100)).setScale(2); }else { bigDecimal = new BigDecimal( b); } return bigDecimal.toPlainString(); } public static void main(String[] args) { // 小数 整数 随便输入 如: 12.12 3434.21 30 List<String> amountList = divideRedPackage("30", 10); BigDecimal total = new BigDecimal("0.00"); for (String amount : amountList) { BigDecimal bigDecimal = new BigDecimal(amount); System.out.println("抢到金额:" + bigDecimal); total =total.add(bigDecimal); } System.out.println("金额total:" + total); }