1. 程式人生 > >Java根據獎品權重計算中獎概率實現抽獎

Java根據獎品權重計算中獎概率實現抽獎

現在在許多網站上都會有抽獎的活動,抽獎的演算法也是多種多樣,這裡介紹一下如何根據每種獎品的權重來抽獎,適用於多種抽獎形式。

這裡寫圖片描述

實體:

 public class Prize {    
    private int id;//獎品id
    private String prize_name;//獎品名稱
    private int prize_amount;//獎品(剩餘)數量
    private int prize_weight;//獎品權重
    //getter、setter

這裡只考慮最簡單的抽獎實現,所以暫時只為獎品設計如上4個欄位。

  見註釋,prize_name表示獎品名稱;prize_amount表示獎品數量,即本次抽獎活動計劃發放此獎品的數量;prize_weight表示獎品權重,表示獎品被抽到的機率的比重,權重越大,被抽到的機率越大,比如本次砸金蛋活動有4種獎品,權重分別是1、2、3、4,總權重是10,那麼每種獎品被抽到的機率就是1/10,2/10,3/10,4/10。

核心演算法:
/**
     * 根據Math.random()產生一個double型的隨機數,判斷每個獎品出現的概率
     * @param prizes
     * @return random:獎品列表prizes中的序列(prizes中的第random個就是抽中的獎品)
     */
    public int getPrizeIndex(List<Prize> prizes) {
        DecimalFormat df = new DecimalFormat("######0.00");  
        int random = -1;
        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(randomNumber >= d1 && randomNumber <= d2){
                    random = i;
                    break;
                }
            }
        }catch(Exception e){
            System.out.println("生成抽獎隨機數出錯,出錯原因:" +e.getMessage());
        }
        return random;
    }

抽獎的邏輯可以用下面這張圖表示:

這裡寫圖片描述

分析:如上圖,為了便於計算和理解,設定每種獎品的權重分別為1,2,3,4,所以被抽到的概率分別為0.1,0.2,0.3,0.4(本次活動中獎概率為100%)。

  先生成一個隨機數randomNumber,然後根據隨機數所處區域判斷獎品:

0<randomNumber<=0.1   表示抽中一等獎
0.1<randomNumber<=0.3 表示抽中二等獎
0.3<randomNumber<=0.6 表示抽中三等獎
0.6<randomNumber<=1.0 表示抽中四等獎

抽獎測試
public static void main(String[] agrs) {
        int i = 0;
        PrizeMathRandom a = new PrizeMathRandom();
        int[] result=new int[4];
        List<Prize> prizes = new ArrayList<Prize>();

        Prize p1 = new Prize();
        p1.setPrize_name("范冰冰海報");
        p1.setPrize_weight(1);//獎品的權重設定成1
        prizes.add(p1);

        Prize p2 = new Prize();
        p2.setPrize_name("上海紫園1號別墅");
        p2.setPrize_weight(2);//獎品的權重設定成2
        prizes.add(p2);

        Prize p3 = new Prize();
        p3.setPrize_name("奧迪a9");
        p3.setPrize_weight(3);//獎品的權重設定成3
        prizes.add(p3);

        Prize p4 = new Prize();
        p4.setPrize_name("雙色球彩票");
        p4.setPrize_weight(4);//獎品的權重設定成4
        prizes.add(p4);

        System.out.println("抽獎開始");
        for (i = 0; i < 10000; i++)// 列印100個測試概率的準確性
        {
            int selected=a.getPrizeIndex(prizes);
            System.out.println("第"+i+"次抽中的獎品為:"+prizes.get(selected).getPrize_name());
            result[selected]++;
            System.out.println("--------------------------------");
        }
        System.out.println("抽獎結束");
        System.out.println("每種獎品抽到的數量為:");
        System.out.println("一等獎:"+result[0]);
        System.out.println("二等獎:"+result[1]);
        System.out.println("三等獎:"+result[2]);
        System.out.println("四等獎:"+result[3]);       
    }

嘗試抽獎10000次的結果如下:
一等獎:962
二等獎:2007
三等獎:3043
四等獎:3988

每類獎品獲獎次數比例剛好大約為1:2:3:4,學過概率的你肯定知道抽獎次數越多,測試結果越準確~~

Tips

  如果計劃中獎率是100%的話,那麼10個獎品只能抽獎10次,所以還要根據實際情況設定每種獎品數量和權重。

  如果需要設定中獎率不為100%,可以新增一個“偽獎品”,併為其設定權重,那麼抽到這個“偽獎品”的概率就是不中獎的概率。

  如果在抽獎過程中某類獎品抽完了,可以做個判斷,如果此獎品的剩餘數量為0,則重新抽取獎品,直到抽到其他獎品位置。