1. 程式人生 > 程式設計 >java實現微信搶紅包演算法

java實現微信搶紅包演算法

簡介

網上說的有兩種比較公平的演算法,一種是二倍均值法,一種是線段切割法。下面我們介紹下兩種演算法的實現:

二倍均值法

原理

剩餘紅包金額M,剩餘人數N,那麼:每次搶到金額=隨機(0,M/N*2)
保證了每次隨機金額的平均值是公平的
假設10人,紅包金額100元
第一人:100/10*2=20,隨機範圍(0,20),平均可以搶到10元
第二人:90/9*2=20,隨機範圍(0,20),平均可以搶到10元
第三人:80/8*2=20,隨機範圍(0,20),平均可以搶到10元
以此類推,每次隨機範圍的均值是相等的
缺點:除了最後一次,任何一次搶到的金額都不會超過人均金額的兩倍,並不是任意的隨機

實現

//二倍均值法
public static List<Integer> divideRedPackage(Integer totalAmount,Integer totalPeopleNum) {
    List<Integer> amountList = new ArrayList<Integer>();
 
    //為了使用random.nextInt(Integer)方法不得不先把紅包金額放大100倍,最後在main函式裡面再除以100
    //這樣就可以保證每個人搶到的金額都可以精確到小數點後兩位
 
    Integer restAmount = totalAmount * 100;
 
    Integer restPeopleNum = totalPeopleNum;
 
    Random random = new Random();
 
    for (int i = 0; i < totalPeopleNum - 1; i++) {
 
      // 隨機範圍:[1,剩餘人均金額的兩倍),左閉右開
 
      int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1;
      restAmount -= amount;
      restPeopleNum--;
      amountList.add(amount);
    }
    amountList.add(restAmount);
 
    return amountList;
  }

線段切割法

原理

把紅包總金額想象成一條很長的線段,而每個人搶到的金額,則是這條主線段所拆分出的若干子線段。

當N個人一起搶紅包的時候,就需要確定N-1個切割點。

因此,當N個人一起搶總金額為M的紅包時,我們需要做N-1次隨機運算,以此確定N-1個切割點。

隨機的範圍區間是[1,100* M)。當所有切割點確定以後,子線段的長度也隨之確定。這樣每個人來搶紅包的時候,只需要順次領取與子線段長度等價的紅包金額即可。

實現

//線段分割法
private static List<Integer> divide(double money,int n) {
    //驗證引數合理校驗
    //為了使用random.nextInt(Integer)方法不得不先把紅包金額放大100倍,最後在main函式裡面再除以100
    //這樣就可以保證每個人搶到的金額都可以精確到小數點後兩位
    int fen = (int) (money * 100);
    if (fen < n || n < 1) {
      System.out.println("紅包個數必須大於0,並且最小紅包不少於1分");
    }
    List<Integer> boards = new ArrayList<>();
    boards.add(0);
    boards.add(fen);
    //紅包個數和板磚個數的關係
    while (boards.size() <= n) {
      int index = new Random().nextInt(fen - 1) + 1;
      if (boards.contains(index)) {
        //保證板子的位置不相同
        continue;
      }
      boards.add(index);
    }
 
    //計算每個紅包的金額,將兩個板子之間的錢加起來
    Collections.sort(boards);
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < boards.size() - 1; i++) {
      Integer e = boards.get(i + 1) - boards.get(i);
      list.add(e);
    }
    return list;
 
  }
  public static void main(String[] args) {
//    List<Integer> accountList = divideRedPackage(50,1000);
    List<Integer> accountList = divide(50,10);
    BigDecimal count = new BigDecimal(0);
    for (Integer amount : accountList) {
      //將搶到的金額再除以100進行還原
      BigDecimal tmpcount = new BigDecimal(amount).divide(new BigDecimal(100));
      count = count.add(tmpcount);
      System.out.println("搶到金額:" + tmpcount);
 
    }
    System.out.println("total=" + count);
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。