红包随机算法,给定一定的金额,一定的人数,保证每个人都能随机获得一定的金额。...

简介: 红包随机算法,给定一定的金额,一定的人数,保证每个人都能随机获得一定的金额。...

前段时间做了一个笔试题,觉得很有意思,特此记录下来。

题目如下

//题目:请编写一个红包随机算法。需求为:给定一定的金额,一定的人数,保证每个人都能随机获得一定的金额。
//比如100元的红包,10个人抢,每人分得一些金额。
//约束条件为,最佳手气金额不能超过最大金额的90%,每人都有红包可抢。
//请给出java代码实现,返回每个人的分配金额并打印出来。

随机分配法

随机法,每次抢红包时计算出本次能够获得的最小金额和最大金额,然后在这个区域间中取一个随机值并计算得出这次抢到的红包金额,这种方法,优点是实现简单,但是,先抢的人会很赚,抢到大红包的概率很高,越到后面的人越吃亏。

public class RedEnvelopMain {
    // 最佳手气获得红包金额,最大金额/总金额,的占比
    public static final double BEST_LUCK_PERCENT = 0.9;
    // 单人每次最小抢到的金额,默认为1分钱
    public static final double ONE_PERSON_MIN_DRAW_AMOUNT = 1;
    /**
     * 拆红包方法
     * 红包金额分配算法
     *
     * @param totalAmount 红包总金额
     * @param personNum   抢红包总人数
     */
    public void redEnvelopLuckyDraw(double totalAmount, int personNum) {
        if (totalAmount <= 0 || personNum < 1) {
            System.out.println("输入参数非法,请检查");
            return;
        }
        // 红包总金额 >= 分配人数 * 每人最小中奖金额
        if (totalAmount < (ONE_PERSON_MIN_DRAW_AMOUNT * personNum)) {
            System.out.println("红包总金额不能小于(中奖人数*单人单次中奖金额),请核对红包金额和发放人数");
            return;
        }
        double minDrawAmount = ONE_PERSON_MIN_DRAW_AMOUNT;
        double maxDrawAmount = totalAmount * BEST_LUCK_PERCENT;
        double drawLuckAmount = 0;
        for (Integer i = 0; i < personNum; i++) {
            int remainPersonNum = personNum - i - 1;
            // 假设剩下的人都中了单人最高金额,那么他此次最少能中的金额
            double othersAllDrawMaxAmountBalance = totalAmount - (maxDrawAmount * remainPersonNum);
            minDrawAmount = minDrawAmount > othersAllDrawMaxAmountBalance ? minDrawAmount : othersAllDrawMaxAmountBalance;
            // 每次抽奖前,计算此次抽奖最大可能出现的金额,假设10人分10元,第一人中8元,则剩下9人,要分2元,此时最大中奖金额发生变化
            //double othersAllDrawMinAmountBalance = totalAmount - (minDrawAmount * remainPersonNum);
            double othersAllDrawMinAmountBalance = totalAmount / remainPersonNum * 2;
            maxDrawAmount = maxDrawAmount < othersAllDrawMinAmountBalance ? maxDrawAmount : othersAllDrawMinAmountBalance;
            drawLuckAmount = (int) Math.floor((maxDrawAmount - minDrawAmount) * Math.random() + minDrawAmount);
            // 每个人抢到红包后,红包内的剩余金额
            totalAmount = totalAmount - drawLuckAmount;
            System.out.println("第" + (i + 1) + "个人抢到:" + drawLuckAmount + "元");
        }
    }
    public static void main(String[] args) {
        RedEnvelopMain redEnvelopMain = new RedEnvelopMain();
        redEnvelopMain.redEnvelopLuckyDraw(100, 10);
    }
}

二倍均值法

假设总金额是M元,N个人,每次抢的金额=(0, (M/N) *2),比如,还是之前说的条件,金额100,人数10,

第一个人抢的金额是 (0,20),抢到的数值,根据正态分布,应该是10左右,远低于10的概率很小,同样远大于10的概率和很小,这里假设第一个人抢到的数值是10;

第二个人抢的金额是(0,90/9 *2)=(0,20),同第一个人,第二个人红包金额也应该是10附近;

余下同理

import java.math.BigDecimal;
import java.util.Objects;
public class RedEnvelopStrongerMain {
    // 最佳手气金额不能超过最大金额的90%
    public static final BigDecimal BEST_LUCK_PERCENT = new BigDecimal(0.9);
    // 单人每次最小抢到的金额,默认为1分钱
    public static final BigDecimal ONE_PERSON_MIN_DRAW_AMOUNT = new BigDecimal(1);
    /**
     * 拆红包方法
     * 红包金额分配算法
     *
     * @param totalAmount    红包总金额
     * @param personQuantity 抢红包总人数
     */
    public void redEnvelopLuckyDraw(BigDecimal totalAmount, Integer personQuantity) {
        if (Objects.isNull(totalAmount) || totalAmount.compareTo(BigDecimal.ZERO) <= 0
                || Objects.isNull(personQuantity) || personQuantity < 1) {
            System.out.println("输入参数非法,请检查");
            return;
        }
        BigDecimal personNum = new BigDecimal(personQuantity);
        // 红包总金额 >= 分配人数 * 每人最小中奖金额
        if (totalAmount.compareTo(ONE_PERSON_MIN_DRAW_AMOUNT.multiply(personNum)) < 0) {
            System.out.println("红包总金额不能小于(中奖人数*单人单次中奖金额),请核对红包金额和发放人数");
            return;
        }
        BigDecimal minDrawAmount = ONE_PERSON_MIN_DRAW_AMOUNT;
        BigDecimal drawLuckAmount;
        for (Integer i = 0; i < personQuantity; i++) {
            Integer remainPersonQuantity = personQuantity - i - 1;
            if (remainPersonQuantity == 0) {
                // 最后一个人,直接把剩余金额返回
                drawLuckAmount = totalAmount;
                totalAmount = totalAmount.subtract(drawLuckAmount);
                System.out.println("第" + (i + 1) + "个人抢到:" + drawLuckAmount + "元");
                break;
            }
            BigDecimal remainPersonNum = new BigDecimal(remainPersonQuantity);
            // 最大不超过剩余金额的90%
            BigDecimal maxDrawAmount = totalAmount.multiply(BEST_LUCK_PERCENT).setScale(2, BigDecimal.ROUND_UP);
            // 二倍均值法,使每个人的中奖金额都按均值概率分布
            BigDecimal doubleAverageAmount = totalAmount.divide(remainPersonNum, 2, BigDecimal.ROUND_UP).multiply(new BigDecimal(2)).setScale(2, BigDecimal.ROUND_UP);
            maxDrawAmount = doubleAverageAmount.compareTo(maxDrawAmount) < 0 ? doubleAverageAmount : maxDrawAmount;
            BigDecimal othersAllDrawMaxAmountBalance = totalAmount.subtract(maxDrawAmount.multiply(remainPersonNum));
            minDrawAmount = othersAllDrawMaxAmountBalance.compareTo(minDrawAmount) < 0 ? minDrawAmount : othersAllDrawMaxAmountBalance;
            drawLuckAmount = (maxDrawAmount.subtract(minDrawAmount)).multiply(new BigDecimal(Math.random())).setScale(2, BigDecimal.ROUND_UP);
            drawLuckAmount = drawLuckAmount.compareTo(minDrawAmount) < 0 ? minDrawAmount : drawLuckAmount;
            // 每个人抢到红包后,红包内的剩余金额
            totalAmount = totalAmount.subtract(drawLuckAmount);
            System.out.println("第" + (i + 1) + "个人抢到:" + drawLuckAmount + "元");
        }
    }
    public static void main(String[] args) {
        RedEnvelopStrongerMain redEnvelopMain = new RedEnvelopStrongerMain();
        redEnvelopMain.redEnvelopLuckyDraw(new BigDecimal(100), 3);
    }
}


本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

原文链接:https://www.cnblogs.com/lingyejun/p/15389021.html



目录
相关文章
|
算法
【MATLAB】逐次变分模态分解SVMD信号分解算法
【MATLAB】逐次变分模态分解SVMD信号分解算法
1310 0
|
2月前
|
存储 人工智能 Java
准确率提升至 90%,阿里商旅基于 AgentScope 构建多智能体差旅助手最佳实践
阿里商旅AliGo通过代码化多智能体架构升级,选用AgentScope框架+Python/Java混合栈+FastAPI,构建“快慢车道”意图识别、实时思考链与流式输出、分层上下文工程及动态Prompt状态机,事项收集准确率从50%提升至90%+,获InfoQ与量子位2025年度AI大奖。
准确率提升至 90%,阿里商旅基于 AgentScope 构建多智能体差旅助手最佳实践
|
人工智能 决策智能 iOS开发
新Siri解锁万能Agent?魔搭开源移动端框架Mobile-Agent-v2抢先体验!
在刚结束的苹果全球开发者大会WWAC上,Apple家族AI全家桶 「Apple Intelligence」亮相,库克宣布个人智能系统将应用于新版本的 iPhone、iPad 和 Mac 操作系统。
|
Web App开发 人工智能 机器人
牛逼,这款开源聊天应用竟能一键召唤多个AI助手,跨平台通话神器!
`JiwuChat`是一款基于Tauri2和Nuxt3构建的轻量化多平台即时通讯工具,仅约8MB体积却集成了**AI群聊机器人**、**WebRTC音视频通话**、**屏幕共享**等前沿功能。一套代码适配Windows/macOS/Linux/Android/iOS/Web六大平台,堪称开发者学习跨端开发的绝佳样板!
533 8
三大运营商那个流量便宜
要确定中国三大运营商(中国移动、中国联通、中国电信)中哪个提供的流量套餐更为便宜,并不是一个可以直接给出固定答案的问题,因为不同的地区、时间、以及用户的具体需求(如通话时长、短信数量、数据流量等)都会影响套餐的价格和性价比。不过,以下是一些通用的方法来比较和选择较为经济的流量套餐:
|
机器学习/深度学习 人工智能 自动驾驶
2024.10|AI/大模型在机器人/自动驾驶/智能驾舱领域的最新应用和深度洞察
本文介绍了AI和大模型在机器人、自动驾驶和智能座舱领域的最新应用和技术进展。涵盖多模态大语言模型在机器人控制中的应用、移动机器人(AMRs)的规模化部署、协作机器人的智能与安全性提升、AR/VR技术在机器人培训中的应用、数字孪生技术的优化作用、Rust语言在机器人编程中的崛起,以及大模型在自动驾驶中的核心地位、端到端自动驾驶解决方案、全球自动驾驶的前沿进展、智能座舱的核心技术演变和未来发展趋势。
1328 2
|
缓存 并行计算 算法
Vulkan 围炉夜话2
Vulkan 围炉夜话
298 13
|
人工智能 决策智能 C++
【AI Agent系列】【阿里AgentScope框架】5. Pipeline模块的组合使用及Pipeline模块总结
【AI Agent系列】【阿里AgentScope框架】5. Pipeline模块的组合使用及Pipeline模块总结
840 1
|
存储 JSON NoSQL
购物车系统设计
在用户选购商品时,下单前,暂存用户想购买的商品。 购物车对数据可靠性要求不高,性能也无特别要求,在整个电商系统是相对容易设计和实现的一个子系统。
1054 0