【实用算法】 红包分配 --- 二倍均值法

二倍均值法

剩余红包金额为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);
    }

猜你喜欢

转载自blog.csdn.net/zy_jun/article/details/131886202