抽奖是一种常用的营销工具。抽奖活动产生至今已许多年,一直被各行各业所采用,原因是它契合了人们的消费心理。对消费者而言,“占便宜”是永恒的追求,“以小博大”也满足了顾客追求刺激的心理。而且与其他活动形式相比,大转盘抽奖活动操作简单,趣味性强,满目奖品吸引用户,参与度高,可以刺激沉睡的用户,是促活拉新的不二之选。
转盘抽奖常常用在提交表单,抽奖定向引流。支付完成订单,抽奖给予概率性的奖励,或者定向引流。
抽奖算法
抽奖算法的基本思想是随机一个数,看随机数落在哪个区间。
现有 A、B、C 三项奖品,概率分别是万分之 10,20,30。则谢谢参与 D(也作为一个奖项)的概率是 10000-10-20-30;
0__ 10 __ 30__60__10000
则获奖区间
A: [0,10]
B: [10,30]
C: [30,60]
D: [60,10000]
random 一个 0-10000 的随机数,落在哪个区间,即中了哪个奖项。
实现代码
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
/**
* @author lvzihai
* @date 2022/4/15
**/
public class LotteryA {
private static int draw(){
int totalCount = 10000;
int pa = 10;
int pb = 20;
int pc = 30;
// 谢谢参与
int pd = totalCount -pa-pb-pc;
int[] gifts = new int[]{pa,pb,pc,pd};
int[] giftRange = new int[gifts.length];
int sum = 0;
for (int i = 0; i < gifts.length; i++) {
sum+=gifts[i];
giftRange[i] = sum;
}
StrUtil s;
int randomVal = RandomUtil.randomInt(totalCount);
for (int i = 0; i < giftRange.length; i++) {
if(randomVal<giftRange[i]){
return i;
}
}
return -1;
}
public static void main (String[] args) {
Map<Integer,Integer> map = new HashMap<>();
int totalCount = 100000;
for (int i = 0; i < totalCount; i++) {
int index = draw();
Integer val = map.get(index);
val = val==null?1:val+1;
map.put(index,val);
}
// 统计概率 万分之X
for (Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey()+" "+10000.0*entry.getValue()/totalCount);
}
}
}
复制代码
总概率不为 1 的算法
对于总概率不为 1 的改进算法。比如概率: A:0.1 B:0.2,C:0.3,D:0.6,将所有概率求和得到总概率,再计算每项的相对概率。
将随机值添加到序列并排序,通过indexOf来获取随机值所在的区间
List<Double> orignalRates = Arrays.asList(0.1,0.2,0.3,0.6);
public static int lottery (List<Double> orignalRates) {
if (orignalRates == null || orignalRates.isEmpty()) {
return -1;
}
int size = orignalRates.size();
// 计算总概率,这样可以保证不一定总概率是1
double sumRate = 0d;
for (double rate : orignalRates) {
sumRate += rate;
}
// 计算每个物品在总概率的基础下的概率情况
List<Double> sortOrignalRates = new ArrayList<Double>(size);
Double tempSumRate = 0d;
for (double rate : orignalRates) {
tempSumRate += rate;
sortOrignalRates.add(tempSumRate / sumRate);
}
// 根据区块值来获取抽取到的物品索引
double nextDouble = Math.random();
// 将随机值添加到序列并排序,通过indexOf来获取随机值所在的区间
sortOrignalRates.add(nextDouble);
Collections.sort(sortOrignalRates);
return sortOrignalRates.indexOf(nextDouble);
}
复制代码
总结
抽奖算法整体思想是把奖项依次排列,谢谢参与也作为一个奖项,排列顺序无关,然后 random 一个随机数,看随机数落在哪个区间,即哪个奖项。对于有库存的奖项,可以单独计算库存,库存用完,直接返回谢谢参与。
评论