java實現微信搶紅包演算法
阿新 • • 發佈:2020-09-25
簡介
網上說的有兩種比較公平的演算法,一種是二倍均值法,一種是線段切割法。下面我們介紹下兩種演算法的實現:
二倍均值法
原理
剩餘紅包金額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); }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。