设一抽奖活动剩余10000元,想按下表所示产品价格及中奖概率最大程度消耗掉余额,如何分配产品笔数?

产品名称 产品价格 产品笔数 中奖概率(%)
P1 10 30
P2 20 30
P3 15 40



思路:

既然给定了中奖概率,则分配出来的笔数应符合预期的概率,概率可取除以最大公约数的结果,用来代表一份符合中奖概率的奖品中应包含各奖品多少个,知道一份奖品中有各奖品多少个之后,可求一份奖品所需金额,总金额除以一份奖品金额,得翻倍倍数,翻倍倍数乘一份中各奖品的个数,得产品笔数



简单计算过程:



1、求中奖概率的最大公约数,得到各产品在符合中奖概率的情况下,所占比重

[30,30,40]最大公约数为10,

则P1、P2、P3占比为 30/10=3,30/10=3, 40/10=4,即3,3,4,

代表符合概率的最少的一份产品中,应包含3个P1,3个P2,4个P3



2、计算符合概率的一份产品能够消耗多少余额

即3个P1,3个P2,4个P3能消耗多少钱

3×10 + 3×20 + 4×15 = 150

即一份产品能消耗150元



3、计算多少份产品能够消耗完余额

即 10000/15=66余100,

即10000元能购买66份符合概率的奖品,剩余100元,为什么剩余100元,因为100元不足以再买一份符合概率的奖品了



4、计算得产品笔数

一份符合概率的奖品中应包含3个P1,3个P2,4个P3,

则66份符合概率的奖品中应包含

P1:3×66=198个

P2:3×66=198个

P3:4×66=264个



扩展情况-小数情况

当要求稍微高一些时,要求中奖概率支持小数的情况,即15.6%、18.9%等,计算过程中会出现一些意外情况下面以支持两位小数举例(实际思路与上述一致)

产品名称 产品价格 产品笔数 中奖概率(%)
P1 10 15.6
P2 20 18.23
P3 15 66.17



第一个问题:小数求最大公约数

最小公约数用笔算我都忘了怎么算了,别说搞代码了,于是百度,得辗转相除法求最大公约数,得求多个数的最大公约数:

    /**
     * 求多个数的最大公约数
     *
     * @param num int集合
     * @param n   集合大小
     * @return 最大公约数
     */
    private static int getMoreBigDiv(Integer[] num, int n) {
        if (n == 1) {
            return num[n - 1];
        }
        return getBigDiv(num[n - 1], getMoreBigDiv(num, n - 1));
    }

    /**
     * 求两个数的最大公约数
     *
     * @param a a
     * @param b b
     * @return a和b最大公约数
     */
    private static int getBigDiv(int a, int b) {
        if (b == 0) {
            return a;
        }
        return getBigDiv(b, a % b);
    }

好家伙,入参int数组,返回int,怎么搞,我入参现在是小数!

首先想到的,入参改成BigDecimal,进来之后再按精度扩大成整数,算出结果来再缩小回去,但是一想,缩小后返回的是小数,在后面的步骤中再用小数有点儿难受,这样不行。

又想到,求公约数的方法不变了,入参前就按精度扩大,后面需要用到这个结果的地方都扩大,在输出结果的时候再缩小,好像也不是不行



那就是

取最大精度:15.6,18.23,66.17,最大精度是2

概率按最大精度放大:1560,1823,6617

求放大后的概率的最大公约数:不巧,这次是1



继续按照简单计算逻辑

求占比:1560/1=1560,1823/1=1823,6617/1=6617,则表示符合概率的最少的一份产品中,应包含1560个P1,1823个P2,6617个P3

一份产品能够消耗的余额:1560×10+1823×20+6617×15=151315



第二个问题,一份奖品所需的金额大于了余额

余额是 10000元,但现在一份满足概率的奖品需要要151315元,则代表,在当前配置下(总余额、单价、概率),无法分配奖品数量。其实这个问题在简单情况下也可能出现,但是在小数情况下更容易出现。假设调整简单情况下的产品价格

产品名称 产品价格 产品笔数 中奖概率(%)
P1 1000 30
P2 2000 30
P3 1500 40

求概率最大公约数得:10,

概率除以最大公约数得:3,3,4

一份奖品所能消耗金额:1000×3+2000×3+1500×4 = 12000元

而余额是10000元,也是不满足的

10000除以151315 或者 10000除以12000,都是不足1的



那就是

在求翻倍倍数时,可能会出现翻倍不足1的情况,这种情况代表,在当前配置下(总余额、单价、概率),无法分配奖品数量



一个完整的小数计算情况

产品名称 产品价格 产品笔数 中奖概率(%)
P1 10 15.6
P2 20 18.2
P3 15 66.2

1、最大精度:2

2、概率按最大精度放大:156,182,662

3、放大后的概率的最大公约数:2

4、放大后的概率除以最大公约数:78,81,331

5、一份奖品所消耗的金额:78×10+81×20+331×15=780+1620+4965=7365

6、翻倍倍数:10000/7365=1余2635

7、P1笔数=78×1=78,P2笔数=81×1=81,P3笔数=331×1=331

得结果

产品名称 产品价格 产品笔数 中奖概率(%)
P1 10
78
15.6
P2 20
81
18.2
P3 15
331
66.2

剩余款项=2635



版权声明:本文为zai_lu_shang__原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/zai_lu_shang__/article/details/123226856