抽奖研究分析

前言

只要是营销的场景,肯定逃不脱抽奖,研究好抽奖可以说是必修课之一,算法也是多种多样,这次以奖品的权重来抽奖。

奖品设置

奖品实体必须含有两个字段,一个用于区分的奖品名称/ID;一个奖品权重
请看表格,进行如下设置


抽奖的逻辑可以用下面这张图表示

算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import java.util.ArrayList;
import java.util.List;

public class PrizeTest {

/**
* 根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率
* @param prizes
* @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
*/
public static int getPrizeIndex(List<Prize> prizes) {
int random = -1;
while(random < 0 ) {
try {
//计算总权重
double sumWeight = 0;
for (Prize p : prizes) {
sumWeight += p.getPrize_weight();
}

//产生随机数
double randomNumber;
randomNumber = Math.random();

//根据随机数在所有奖品分布的区域并确定哪个名称里
double d1 = 0;
double d2 = 0;
for (int i = 0; i < prizes.size(); i++) {
d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight())) / sumWeight;
if (i == 0) {
d1 = 0;
} else {
d1 += Double.parseDouble(String.valueOf(prizes.get(i - 1).getPrize_weight())) / sumWeight;
}
if (d1 <= randomNumber && randomNumber < d2) {
random = i;
break;
}
}
} catch (Exception e) {
System.out.println("出错原因:" + e.getMessage());
}
}
return random;
}

public static void main(String[] agrs) {
int i = 0;
List<Prize> prizes = new ArrayList<Prize>();

Prize p1 = new Prize();
p1.setPrize_name("名称1");
p1.setPrize_weight(1);//权重设置成1
prizes.add(p1);

Prize p2 = new Prize();
p2.setPrize_name("名称2");
p2.setPrize_weight(2);//权重设置成2
prizes.add(p2);

Prize p3 = new Prize();
p3.setPrize_name("名称3");
p3.setPrize_weight(3);//权重设置成3
prizes.add(p3);

Prize p4 = new Prize();
p4.setPrize_name("名称4");
p4.setPrize_weight(4);//权重设置成4
prizes.add(p4);
int[] result=new int[prizes.size()];

System.out.println("开始.。。");
for (i = 0; i < 100; i++)// 打印100个测试概率的准确性
{
System.out.println("第"+i+"次使用:"+prizes.get(getPrizeIndex(prizes)).getPrize_name());
result[getPrizeIndex(prizes)]++;
System.out.println("--------------------------------");
}
System.out.println("结束。。。");
System.out.println("每家供应商的使用数量为:");
System.out.println("名称1:"+result[0]);
System.out.println("名称2:"+result[1]);
System.out.println("名称3:"+result[2]);
System.out.println("名称4:"+result[3]);
}

static class Prize{
private String prize_name;//名称
private int prize_weight;//权重

public String getPrize_name() {
return prize_name;
}

public void setPrize_name(String prize_name) {
this.prize_name = prize_name;
}

public int getPrize_weight() {
return prize_weight;
}

public void setPrize_weight(int prize_weight) {
this.prize_weight = prize_weight;
}
}
}

打开终端,对PrizeTest进行编译,然后运行

1
2
javac PrizeTest.java
java PrizeTest

得出的结果

结束。。。
每个奖品名称的使用数量为:
名称1:9
名称2:26
名称3:25
名称4:40

设置的奖品数量只有100,计算的结果基本符合预期,数字越大,越准确。

其他情况

如果预想中奖率是100%,那么10个奖品只能抽奖10次,所以还要根据实际情况设置每种奖品数量和权重。
如果需要设置中奖率不为100%,可以添加一个“伪奖品”进行站位,为其设置权重,那么抽到这个“伪奖品”的概率就是不中奖的概率。
这个是在奖品充足的时候情况下,如果在抽奖活动中某个奖品抽完了,做个判断,即此奖品剩余数量为0,则重新抽取一次,一直到抽到其他还有剩余的奖项为止。

参考的资料是要联动数据库的,这里做了一些简单的处理,理解核心业务逻辑。

参考资料:https://blog.csdn.net/a46788304/article/details/65437754