设一抽奖活动剩余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