使用二倍均值法完成红包算法

大家好 , 我是安心君 这是我在博客园的第二篇博客 ,这次我打算分享下抢红包的算法.这里先把红包算法的要求概述一下:

1.所有人抢到红包金额的总和要恰好等于红包总金额 不能多也不能少.

2.所有人抢到红包金额的大小应该全凭运气 保证公平

3.每个人最低获得0.01元

这就是红包算法的基本要求 .  很多朋友的第一想法是不是让每个人从剩余金额那里拿金额  就是用随机数r.nextInt(residualMoney);这确实是最容易想到的一种方法 但仔细想想 这个算法好像只满足了第一个条件  首先范围是从[0,residualMoney) 是可以取到0的 没有保证每个人至少分到0.01元   再一个这个算法其实不能保证每个人取到任意金额的概率都是相等的 说白了就是没有保证红包算法的公平性. 

大家可以想想看  如果100块钱给十个人分 那么第一个人获得金额的返回是从(0,100],即数学期望是50元 第二个人则是从(0,50)开始取了 期望变成了25元 可以推得 每下一个人的数序期望是前一个人的一半

所以我们可以从期望入手 让每个人不管先后顺序 取得金额的数学期望是相等的 那么这个红包算法就是公平的  

这里我们介绍一个二倍均值法

/**

剩余红包金额为M,剩余人数为N,那么有如下公式:

每次抢到的金额 = 随机区间 (0, M / N X 2)

这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平。

举个栗子:

假设有10个人,红包总额100元。

100/10X2 = 20, 所以第一个人的随机范围是(0,20 ),平均可以抢到10元。

假设第一个人随机到10元,那么剩余金额是100-10 = 90 元。

90/9X2 = 20, 所以第二个人的随机范围同样是(0,20 ),平均可以抢到10元。

假设第二个人随机到10元,那么剩余金额是90-10 = 80 元。

80/8X2 = 20, 所以第三个人的随机范围同样是(0,20 ),平均可以抢到10元。

以此类推,每一次随机范围的均值是相等的。 

转载*/

 当然肯定不能从0开始随机 我们还得保证每个人分得的钱至少是0.01元; (具体解释详见代码分析)

    1. //发红包算法,金额参数以分为单位
    2.  
      public static List<Integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum){
    3.  
         List<Integer> amountList = new ArrayList<Integer>();
    4.  
         Integer restAmount = totalAmount;
    5.  
         Integer restPeopleNum = totalPeopleNum;
    6.  
         Random random = new Random();
    7.  
         for(int i=0; i<totalPeopleNum-1; i++){
    8.  
             //随机范围:[1,剩余人均金额的两倍),左闭右开
    9.  
             int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1;
    10.  
             restAmount -= amount;
    11.  
             restPeopleNum --;
    12.  
             amountList.add(amount);
    13.  
         }
    14.  
         amountList.add(restAmount);
    15.  
         return amountList;
    16.  
      }
    17.  
      public static void main(String[] args){
    18.  
         List<Integer> amountList = divideRedPackage(5000, 30);
    19.  
         for(Integer amount : amountList){
    20.  
             System.out.println("抢到金额:" + new BigDecimal(amount).divide(new BigDecimal(100)));
    21.  
         }
    22.  
      }(转载)
      其实思路挺简单的 指点就在我加粗的代码 
      首先先把范围规定到[0.01,residualMoney)     //1/100 = 0.01
      如果所有人都这样随机的话 可能会有金额没有被取到
      所以前面人先随机去取 然后最有一人再分的剩下的所有金额 
       
      这样我们的目的就达到了!!!!!!
原文地址:https://www.cnblogs.com/j-1-z-2-s-3/p/13245991.html