4类抽奖算法总结


第一类是常见的有等级的抽奖活动,如一等、二等、三等奖等等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 分别为一、二、三、四等将的奖品数量,最后一个为未中奖的数量。  
     private  static  final  Integer[] lotteryList = { 5 10 20 40 100 };  
   
     private  int  getSum() {  
         int  sum =  0 ;  
         for  ( int  v : lotteryList) {  
             sum += v;  
         }  
         return  sum;  
     }  
   
     private  int  getLotteryLevel() {  
         Random random =  new  Random(System.nanoTime());  
         int  sum = getSum();  
         for  ( int  i =  0 ; i < lotteryList.length; ++i) {  
             int  randNum = Math.abs(random.nextInt()) % sum;  
             if  (randNum <= lotteryList[i]) {  
                 return  i;  
             else  {  
                 sum -= lotteryList[i];  
             }  
         }  
         return  - 1 ;  
     }

第二类是不分等级的抽奖活动,仅需要参与人数与奖品总数,各奖品中奖概率相等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//另一种抽奖算法,用于公司抽奖,即总参与人数与奖品数固定。  
     private  static  final  int  lotteryNum =  75 ;  
     private  static  final  int  total =  175 ;  
     private  static  Set<Integer> lotterySet =  new  HashSet<Integer>();  
     static  {  
         for  ( int  i= 1 ; i <= lotteryNum; ++i) {  
             lotterySet.add(total*i/lotteryNum);  
         }  
     }  
     private  int  getLotteryNum2() {  
         Random rand =  new  Random(System.nanoTime());  
         int  randNum = Math.abs(rand.nextInt()) % total;  
         if  (lotterySet.contains(randNum)) {  
             return  randNum*lotteryNum/total;  
         }  
         return  - 1 ;  
     }

第三类  一个商场进行一场抽奖活动,其中有两个奖项,第一个奖项A抽中的概率是1/6,第二个奖项B抽中的概率是5/6;编码实现这个抽奖程序。

思路:

这题考察队随机函数的应用。

由于rand()函数产生的随机数的范围是0-65535,那么将该随机数对6求余,得到的数在0-5之间,且每个数出现概率相等。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstdlib>  
  4. #include <ctime>  
  5. #include <algorithm>  
  6. using namespace std;  
  7.   
  8. char Draw()  
  9. {  
  10.     int num = rand() % 6;  
  11.     if (num == 0) return 'A';  
  12.     else return 'B';  
  13. }  
  14.   
  15. int main()  
  16. {  
  17.     srand((unsigned int)time(0)); //注意:srand函数一定不能在循环里  
  18.     for (int i = 0; i < 36; i++)  
  19.     {  
  20.         cout << Draw() << endl;  
  21.     }  
  22.     return 0;  
  23. }  



第四类 : 不同概率抽奖
序号物品名称物品ID抽奖概率
1物品1P10.2
2物品2
P2
0.1
3物品3
P3
0.4
4物品4
P4
0.3
5物品5
P5
0.0
6物品6
P6
-0.1
7物品7
P7
0.008


  • VO类:Gift.java    具体对应就是上面表格里的内容
public class Gift {
    private int index;
    private String gitfId;
    private String giftName;
    private double probability;

    public Gift(int index, String gitfId, String giftName, double probability) {
        this.index = index;
        this.gitfId = gitfId;
        this.giftName = giftName;
        this.probability = probability;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getGitfId() {
        return gitfId;
    }

    public void setGitfId(String gitfId) {
        this.gitfId = gitfId;
    }

    public String getGiftName() {
        return giftName;
    }

    public void setGiftName(String giftName) {
        this.giftName = giftName;
    }

    public double getProbability() {
        return probability;
    }

    public void setProbability(double probability) {
        this.probability = probability;
    }

    @Override
    public String toString() {
        return "Gift [index=" + index + ", gitfId=" + gitfId + ", giftName=" + giftName + ", probability=" + probability + "]";
    }

}
  • Util类:LotteryUtil.java    真正的不同概率的抽奖工具类
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 不同概率抽奖工具包
 *
 * @author Shunli
 */
public class LotteryUtil {
    /**
     * 抽奖
     *
     * @param orignalRates
     *            原始的概率列表,保证顺序和实际物品对应
     * @return
     *         物品的索引
     */
    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();
        sortOrignalRates.add(nextDouble);
        Collections.sort(sortOrignalRates);

        return sortOrignalRates.indexOf(nextDouble);
    }
}
  • Test类:Test.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 不同概率抽奖
 *
 * @author ShunLi
 */
public class LotteryTest {
    public static void main(String[] args) {
        List<Gift> gifts = new ArrayList<Gift>();
        // 序号==物品Id==物品名称==概率
        gifts.add(new Gift(1, "P1", "物品1", 0.2d));
        gifts.add(new Gift(2, "P2", "物品2", 0.2d));
        gifts.add(new Gift(3, "P3", "物品3", 0.4d));
        gifts.add(new Gift(4, "P4", "物品4", 0.3d));
        gifts.add(new Gift(5, "P5", "物品5", 0d));
        gifts.add(new Gift(6, "P6", "物品6", -0.1d));
        gifts.add(new Gift(7, "P7", "物品7", 0.008d));

        List<Double> orignalRates = new ArrayList<Double>(gifts.size());
        for (Gift gift : gifts) {
            double probability = gift.getProbability();
            if (probability < 0) {
                probability = 0;
            }
            orignalRates.add(probability);
        }

        // statistics
        Map<Integer, Integer> count = new HashMap<Integer, Integer>();
        double num = 1000000;
        for (int i = 0; i < num; i++) {
            int orignalIndex = LotteryUtil.lottery(orignalRates);

            Integer value = count.get(orignalIndex);
            count.put(orignalIndex, value == null ? 1 : value + 1);
        }

        for (Entry<Integer, Integer> entry : count.entrySet()) {
            System.out.println(gifts.get(entry.getKey()) + ", count=" + entry.getValue() + ", probability=" + entry.getValue() / num);
        }
    }

}



不同概率的抽奖原理很简单 
就是把0到1的区间分块,而分块的依据就是物品占整个的比重,再根据随机数种子来产生0-1中间的某个数,来判断这个数是落在哪个区间上,而对应的就是抽到了那个物品。随机数理论上是概率均等的,产生的每个数理论上也应该概率均等,那么相应的区间所含数的多少就体现了抽奖物品概率的不同。(p.s. 当然数目是数不清楚的,具体抽象话了点)

这个实例的数据可以说明 
1. 概率可以是负数和0,当然实际上中应该不会(p.s. 正常情况下可能真的有0,比如抽个iphone5,当然是抽不到的了,这个时候,构建礼物(List gifts)的时候最好就不要加这个进去),还有可以把负数的处理放到抽奖工具类(LotteryUtil)中; 
2. 所有礼物加起来的概率可以不是1,可以认为这里的概率是一个权重;


  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值