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

2023-05-16

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

题目如下

//题目:请编写一个红包随机算法。需求为:给定一定的金额,一定的人数,保证每个人都能随机获得一定的金额。
//比如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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • VMware下使用Gparted对系统盘扩容

    第一步 xff0c 下载Gparted的iso镜像文件 xff0c 这里对应下载相应的32或者64位版本 第二步 xff0c 设置虚拟机 xff0c 将硬盘容量扩容为指定的容量 xff0c 保存 第三步 xff0c 设置虚拟机 xff0c
  • Android系统深度游

    项目原因 xff0c 让我们必须深入探索Android系统 xff0c 完成对之前的我们来说比较艰巨的任务 这样 xff0c 我们开启了Android深度游 Android这个系统 xff0c 应用层开发还是比较舒服的 xff0c Goog
  • IT痴汉的工作现状56-耳鸣

    自从这个项目启动 xff0c 与客户方的沟通就逐渐多了起来 xff0c 沟通的方式是语音会议 也不知从什么时候起 xff0c 每天的会议时间变得很长很长 尤其是定位复杂问题时 xff0c 一个会议就要4个小时 张伟是从项目开始买的耳机 xf
  • 我的2020---熬过去

    恰逢周末 xff0c 本人自认为过了一个美好的圣诞节之后 xff0c 在深圳图书馆开始思考我的第十一个年终总结了 提笔之前 xff0c 我翻看了去年的总结 xff0c 想到了我还有一套书没有读完 xff0c 那就是 大败局 2020结束还有
  • 我的2022-工程师文化的思考

    没有想到 xff0c 今年大环境的变化可谓是大开大合 xff0c 超出想象 各行各业都遭到强大的挑战 xff0c 是泯灭还是苟活 xff0c 亦或是再创辉煌 xff0c 时也命也 在此情况下的个人 xff0c 最好的选择是跟公司抱团取暖 x
  • 用户名 不在 sudoers文件中,此事将被报告。

    继续昨天的故事 话说昨天新建了一个帐号linc xff0c 今天在执行sudo时回显一个很吓人的信息 xff1a sudo password for linc linc 不在 sudoers 文件中 此事将被报告 这是要去哪儿报告呢 xff
  • Git冲突:commit your changes or stash them before you can merge.

    今天用git pull来更新代码 xff0c 遇到了下面的问题 xff1a error Your local changes to the following files would be overwritten by merge xxx
  • Android问题集锦之二十八:You need to use a Theme.AppCompat theme (or descendant) with this activity.

    错误描述为 xff1a java lang IllegalStateException You need to use a Theme AppCompat theme or descendant with this activity 起因
  • Docker实践6:Cannot connect to the Docker daemon.

    正在免费适用着Aliyun主机 xff0c 当然要用docker来部署我的服务器啦 但是今天碰到了题目的问题 xff0c 细节如下 xff1a span class hljs comment docker info span FATA sp
  • DFS与BFS总结

    总结 bfs多用于在一次选择中可以有多种情况的选择 而dfs是确定唯一性如唯一路径 xff0c 也就是深度 当问题是全盘式的搜索 xff0c 不在乎形式或者具体情况呈现还是详细过程的 xff0c 使用bfs 当问题是要求具体过程 xff0c
  • 一个简单的自定义通信协议(socket)

    转自 xff1a http vtrtbb javaeye com blog 849336 这是转自javaeye的一篇文章 xff0c 作者是vtrtbb 按照网络通信的传统 xff0c 我们都会自定义协议 xff0c 这有很多好处 xff
  • ImageView 设置图片

    android doc中是这样描述的 xff1a public void setImageResource int resId 这是其中的一个方法 xff0c 参数resld是这样 xff1a ImageView setImageResou
  • Android问题集锦之八:调用其他程序中的activity和Permission Denial: starting Intent 错误解决办法

    今天想调试多个task中栈的情况 xff0c 在测试程序中调用另一个程序的activity xff0c 代码片段如下 xff1a btnStartX 61 Button findViewById R id btnStartX btnStar
  • VB.NET串口通信例子--我的回忆录

    这是我3年前的一个例子 xff0c 最近翻出来回忆一下 串口是计算机上一种非常通用设备通信的协议 大多数计算机包含两个基于RS232的串口 xff0c 现在配电脑好像只有一个 串口同时也是仪器仪表设备通用的通信协议 xff1b 很多GPIB
  • TensorFlowLite GPU加速

    官方文档 https tensorflow google cn lite performance gpu hl 61 zh cn TF LITE支持移动端GPU加速 xff0c 特别对android端的支持比较丰富 相对android来说
  • C语言基础----流程控制

    流程控制是C语言中比较基础的 它分为三种状态 xff1a 1是顺序结构 2是选择结构 3是循环结构 我要说明后两种结构 xff0c 选择机构和循环结构 首先先说 xff1a 选择结构 选择结构是指 xff1a 当一个条件成立则执 xff08
  • 复杂数据类型——数组

    复杂数据类型是C语言基础的重点 1 数组 xff1a 存储一组数据 2 特点 xff1a 只能存放一种类型的数据 如int类型 xff0c float类型的数据 数组的元素个数只可以放常量 int ages 5 61 1 2 3 格式 xf
  • OC语言——基本语法和思想

    今天学习了OC语言基础语法 1 oc语言完全兼容C语言 xff0c 后缀为 m类型 被广泛应运与开发苹果mac os x平台和ios开发平台 2 oc语言关键字基本上以 64 开头 xff0c oc字符串也是以 64 开头 3 基本类型新加
  • OC语言——三大特性-继承与多态

    继承是oc中比较常见的 1 继承 xff1a 就是当两个类拥有相同的属性和方法时 xff0c 就可以将相同的东西抽取到一个父类中 子类可以拥有父类中所有的成员变量和方法 2 继承的好处 xff1a 可以抽取重复代码 xff0c 节省时间 建
  • OC语言——点语法和成员变量的4种作用域及property和synthesize的使用

    点语法 xff1a 点语法的本质还是方法调用 Person p 61 Person new 点语法的本质还是方法调用 p age 61 10 p setAge 10 一 点语法注意点 xff1a 64 implementation Pers

随机推荐

  • 树排序的理解

    参考文献与详细资料 xff1a https blog csdn net weixin 64067830 article details 124443430 视频 https www bilibili com video BV1iU4y1B7
  • OC语言——构造方法和分类的使用

    一 构造方法 1调用 43 alloc分配存储空间 Person p 61 Person alloc 2初始化 init Person p1 61 p init 可以整合为一句 Person p2 61 Person alloc init
  • 使用CSDN-markdown

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传
  • 【笔试&面试】关于动态链接库

    动态链接库英文为DLL xff0c 是Dynamic Link Library 的缩写形式 xff0c DLL 是一个包含可由多个程序同时使用的代码和数据的库 xff0c DLL 不是可执行文件 动态链接提供了一种方法 xff0c 使进程可
  • 虚函数表的实现细节

    1 虚函数 虚表是怎么实现的 xff1f 虚表存放在哪里 xff1f 虚表中的数据是在什么时候确定的 xff1f 对象中的虚表指针又在什么时候赋值的 xff1f 我们很难通过 C 43 43 语言本身来找到答案 C 43 43 标准给编译器
  • 三种工厂模式区别总结

    工厂模式分为三种 xff1a 简单工厂 工厂模式和抽象工厂模式 三者之间存在哪些异同呢 xff1f 先分别看看各个模式的特点 一 简单工厂模式 xff1a 实现了算法和界面的分离 xff0c 也就是将业务逻辑和界面逻辑分开了 xff0c 降
  • 快速排序 改进快排的方法

    快速排序法事应用最广泛的排序算法之一 xff0c 最佳情况下时间复杂度是 O nlogn 但是 最坏情况下可能达到 O n 2 说明快速排序达到最坏情况的原因 并提出改善方案并实现 之 答 xff1a 改进方案 xff1a 改进选取枢轴的方
  • linux select函数详解

    在 Linux 中 xff0c 我们可以使用 select 函数实现 I O 端口的复用 xff0c 传递给 select 函数的参数会告诉内核 xff1a 我们所关心的文件描述符 对每个描述符 xff0c 我们所关心的状态 我们是要想从一
  • Linux epoll详解

    Linux epoll详解 一 什么是epoll epoll是什么 xff1f 按照man手册的说法 xff1a 是为处理大批量句柄而作了改进的poll 当然 xff0c 这不是2 6内核才有的 xff0c 它是在2 5 44内核中被引进的
  • 转折后的总结--2014年找工作

    转折后的总结 找工作 好吧 xff0c 还是忍不住做个总结 xff0c 毕竟还是我人生中一次比较大的事件了 非常感谢华科 xff0c 我的第二个母校能提供给我一个优秀的平台 非常感谢信息安全与保密实验室607室的老师们 xff0c 给我诸多
  • 2014找工作总结-机会往往留给有准备的人

    好基友的文章必须转 xff0c 大神一枚 xff1a 出处 xff1a http blog csdn net xiajun07061225 article details 12844801 其实我的求职过程在十一之前就已经结束了 xff0c
  • 1020 Tree Traversals

    Suppose that all the keys in a binary tree are distinct positive integers Given the postorder and inorder traversal sequ
  • 入职后的书单

    程序员一生的命运就是不停的学习 xff0c 淬炼自己的技术 xff0c 转化为自己的经验 作为新手 xff0c 首先要读的应该是 xff1a 代码整洁之道 1 JAVA核心技术 xff08 卷1 xff09 作者 Cay S Horstma
  • 国内第一本详解云GIS技术的参考书籍《云GIS技术与实践》

    书籍封面 内容简介 云计算技术从概念提出到项目落地已经经历了十余年了 xff0c GIS技术也紧跟IT主流技术大潮 xff0c 通过日趋成熟的云计算技术来解决GIS面临的诸多问题 一转眼 xff0c 云GIS技术也发展了五个年头了 xff0
  • jetpack之ViewModel

    ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据 ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存 摘自官方文档 Android 框架可以管理界面控制器 xff08 如 Activity 和 Fragmen
  • 二叉树的各种创建方法

    1 前序创建 include lt stdlib h gt include lt malloc h gt include lt iostream gt include lt stack gt include lt queue gt usin
  • 虚拟机创建、发放与迁移

    虚拟机创建方法 xff1a 创建空虚拟机虚拟机克隆虚拟机 xff1a 虚拟机运行状态是可以克隆虚拟机的按照模板部署虚拟机 xff1a 模板存在 xff0c 可以调整参数 xff0c 批量部署模板转为虚拟机 xff1a 模板不存在 xff0c
  • Linux必学书籍!五本强烈推荐,你读过几本?

    深入理解Linux内核 推荐等级 xff1a 5颗星 为了透彻理解Linux的工作机理 xff0c 以及为何它在各种系统上能顺畅运行 xff0c 你需要深入到内核的心脏 cPu与外部世界的所有交互活动都是由内核处理的 xff0c 哪些程序会
  • 一个毕业6年的程序员工作经历和成长感悟(终)

    接上篇 xff1a 一个毕业6年的程序员工作经历和成长感悟 xff08 上 xff09 一个毕业6年的程序员工作经历和成长感悟 xff08 中 xff09 一个毕业6年的程序员工作经历和成长感悟 xff08 下 xff09 回望过去 6 年
  • 红包随机算法,给定一定的金额,一定的人数,保证每个人都能随机获得一定的金额。...

    前段时间做了一个笔试题 xff0c 觉得很有意思 xff0c 特此记录下来 题目如下 题目 请编写一个红包随机算法 需求为 xff1a 给定一定的金额 xff0c 一定的人数 xff0c 保证每个人都能随机获得一定的金额 比如100元的红包