紅包分配問題 給你一個整數表示紅包的總額,和另一個整數表示紅包的個數 表示我們要把總金額,隨機分成N個紅包。 要求1:每個紅包的金額都是隨機的 要求2:每個人至少1分錢 示例代碼: 1 public class Test2 { 2 public static void main(String[] a ...
紅包分配問題
給你一個整數表示紅包的總額,和另一個整數表示紅包的個數
表示我們要把總金額,隨機分成N個紅包。
要求1:每個紅包的金額都是隨機的
要求2:每個人至少1分錢
示例代碼:
1 public class Test2 { 2 public static void main(String[] args) { 3 System.out.println(Arrays.toString(luckyMoney("150.01", 10))); 4 } 5 6 public static BigDecimal[] luckyMoney(String money,int n){//紅包金額/元,紅包個數 7 double money1= 0; 8 try { 9 money1 = Double.parseDouble(money); 10 } catch (NumberFormatException e) { 11 System.out.println("輸入金額錯誤!"); 12 e.printStackTrace(); 13 return null; 14 } 15 //System.out.println(money1); 16 int total=(int) (money1*100);//因為人民幣的金額最小擋位為分,可以先將紅包的金額轉化為以分為單位,轉化成整型 17 int rest=total-n;//紅包剩餘金額,因為每個紅包的最小金額為1分,所以可以把每個紅包的初始量設為1分 18 int[] luckMoney=new int[n]; 19 Random r = new Random(); 20 for (int i = 0; i < luckMoney.length; i++) { 21 if (i==luckMoney.length-1){//最後一個紅包金額等於紅包金額的最後剩餘量+1分 22 luckMoney[luckMoney.length-1]=1+rest; 23 break; 24 } 25 if (rest>0){ 26 int temp=r.nextInt(rest+1);// 27 luckMoney[i]=1+temp; 28 rest-=temp; 29 }else {//紅包剩餘金額已經分配完了,剩餘紅包的金額都為1分 30 luckMoney[i]=1; 31 } 32 } 33 BigDecimal[] luckMoney1=new BigDecimal[n];//這裡用BigDecimal數組來記錄紅包的金額,因為BigDecimal進行計算時不會丟失精度 34 //BigDecimal sum = new BigDecimal("0"); 35 for (int i = 0; i < luckMoney.length; i++) { 36 BigDecimal a = new BigDecimal(""+luckMoney[i]); 37 BigDecimal b = new BigDecimal("100"); 38 luckMoney1[i]= a.divide(b,2,BigDecimal.ROUND_HALF_UP);//轉化以元為單位時,除以100,應保留兩位小數 39 sum=sum.add(luckMoney1[i]); 40 } 41 //System.out.println(sum); 42 return luckMoney1; 43 } 44 }
運行結果:
[16.50, 19.03, 64.12, 30.99, 8.96, 1.57, 2.10, 5.22, 0.04, 1.48]
[17.18, 112.52, 5.46, 0.97, 6.43, 3.26, 1.88, 1.27, 0.95, 0.09]
[82.38, 23.82, 14.27, 18.89, 4.31, 1.34, 4.16, 0.34, 0.12, 0.38]
這個演算法雖然能達到隨機分配紅包金額的功能,但由上面運行結果我們不難發現,越往後紅包分配的可金額越小,而且紅包分配不夠均勻
為了保證每個紅包金額分配額度的合理,
額度應該在0.01和剩餘平均值×2之間。例如:發100塊錢,總共10個紅包,那麼平均值是10塊錢一個,那麼發出來的紅包的額度在0.01元~20元之間波動。當前面3個紅包總共被領了40塊錢時,剩下60塊錢,總共7個紅包,那麼這7個紅包的額度在:0.01~(60/7×2)=17.14之間。 修改後的代碼為
1 public class Test2 { 2 public static void main(String[] args) { 3 System.out.println(Arrays.toString(luckyMoney("150.01", 10))); 4 } 5 6 public static BigDecimal[] luckyMoney(String money,int n){ 7 double money1= 0; 8 try { 9 money1 = Double.parseDouble(money); 10 } catch (NumberFormatException e) { 11 System.out.println("輸入金額錯誤!"); 12 e.printStackTrace(); 13 return null; 14 } 15 System.out.println(money1); 16 int total=(int) (money1*100); 17 int rest=total-n; 18 int restNum=n;//剩餘紅包個數 19 int[] luckMoney=new int[n]; 20 Random r = new Random(); 21 for (int i = 0; i < luckMoney.length; i++) { 22 if (i==luckMoney.length-1){ 23 luckMoney[luckMoney.length-1]=1+rest; 24 break; 25 } 26 if (rest>0){ 27 int temp=r.nextInt(rest*2/restNum+1);//修改處 28 restNum--; 29 luckMoney[i]=1+temp; 30 rest-=temp; 31 }else { 32 luckMoney[i]=1; 33 } 34 } 35 BigDecimal[] luckMoney1=new BigDecimal[n]; 36 BigDecimal sum = new BigDecimal("0"); 37 for (int i = 0; i < luckMoney.length; i++) { 38 BigDecimal a = new BigDecimal(""+luckMoney[i]); 39 BigDecimal b = new BigDecimal("100"); 40 luckMoney1[i]= a.divide(b,2,BigDecimal.ROUND_HALF_UP); 41 sum=sum.add(luckMoney1[i]); 42 } 43 System.out.println(sum); 44 return luckMoney1; 45 } 46 }
運行結果:
[7.21, 30.82, 26.08, 21.54, 7.81, 22.19, 9.72, 15.15, 3.89, 5.60]
在紅包拆開之前,每個人,無論先後順序,搶到的紅包金額的數學期望都是一樣的,如果100元分成5個紅包,那麼每個人搶到的金額的數學期望就是20元,但有趣的是,雖然數學期望一樣,但概率密度卻有很大差別。如果想詳細瞭解紅包分配的問題可以閱讀這篇知乎文獻:微信紅包金額分配的演算法是怎樣的?誰比較容易到最佳手氣?誰有機會拿到較大的金額? - Jingchi Wang的回答 - 知乎 https://www.zhihu.com/question/28250396/answer/86302251