ToB企服应用市场:ToB评测及商务社交产业平台

标题: 红包分配问题 [打印本页]

作者: 立山    时间: 2023-7-11 19:46
标题: 红包分配问题
红包分配问题

给你一个整数表示红包的总额,和另一个整数表示红包的个数
表示我们要把总金额,随机分成N个红包。
要求1:每个红包的金额都是随机的
要求2:每个人至少1分钱
 
示例代码:
  1. 1 public class Test2 {
  2. 2     public static void main(String[] args) {
  3. 3         System.out.println(Arrays.toString(luckyMoney("150.01", 10)));
  4. 4     }
  5. 5
  6. 6     public static BigDecimal[] luckyMoney(String money,int n){//红包金额/元,红包个数
  7. 7         double money1= 0;
  8. 8         try {
  9. 9             money1 = Double.parseDouble(money);
  10. 10         } catch (NumberFormatException e) {
  11. 11             System.out.println("输入金额错误!");
  12. 12             e.printStackTrace();
  13. 13             return null;
  14. 14         }
  15. 15         //System.out.println(money1);
  16. 16         int total=(int) (money1*100);//因为人民币的金额最小挡位为分,可以先将红包的金额转化为以分为单位,转化成整型
  17. 17         int rest=total-n;//红包剩余金额,因为每个红包的最小金额为1分,所以可以把每个红包的初始量设为1分
  18. 18         int[] luckMoney=new int[n];
  19. 19         Random r = new Random();
  20. 20         for (int i = 0; i < luckMoney.length; i++) {
  21. 21             if (i==luckMoney.length-1){//最后一个红包金额等于红包金额的最后剩余量+1分
  22. 22                 luckMoney[luckMoney.length-1]=1+rest;
  23. 23                 break;
  24. 24             }
  25. 25             if (rest>0){
  26. 26                 int temp=r.nextInt(rest+1);//
  27. 27                 luckMoney[i]=1+temp;
  28. 28                 rest-=temp;
  29. 29             }else {//红包剩余金额已经分配完了,剩余红包的金额都为1分
  30. 30                 luckMoney[i]=1;
  31. 31             }
  32. 32         }
  33. 33         BigDecimal[] luckMoney1=new BigDecimal[n];//这里用BigDecimal数组来记录红包的金额,因为BigDecimal进行计算时不会丢失精度
  34. 34         //BigDecimal sum = new BigDecimal("0");
  35. 35         for (int i = 0; i < luckMoney.length; i++) {
  36. 36             BigDecimal a = new BigDecimal(""+luckMoney[i]);
  37. 37             BigDecimal b = new BigDecimal("100");
  38. 38             luckMoney1[i]= a.divide(b,2,BigDecimal.ROUND_HALF_UP);//转化以元为单位时,除以100,应保留两位小数
  39. 39             sum=sum.add(luckMoney1[i]);
  40. 40         }
  41. 41         //System.out.println(sum);
  42. 42         return luckMoney1;
  43. 43     }
  44. 44 }
复制代码
运行结果:
  1. [16.50, 19.03, 64.12, 30.99, 8.96, 1.57, 2.10, 5.22, 0.04, 1.48]
复制代码
  1. [17.18, 112.52, 5.46, 0.97, 6.43, 3.26, 1.88, 1.27, 0.95, 0.09]
复制代码
  1. [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. 1 public class Test2 {
  2. 2     public static void main(String[] args) {
  3. 3         System.out.println(Arrays.toString(luckyMoney("150.01", 10)));
  4. 4     }
  5. 5
  6. 6     public static BigDecimal[] luckyMoney(String money,int n){
  7. 7         double money1= 0;
  8. 8         try {
  9. 9             money1 = Double.parseDouble(money);
  10. 10         } catch (NumberFormatException e) {
  11. 11             System.out.println("输入金额错误!");
  12. 12             e.printStackTrace();
  13. 13             return null;
  14. 14         }
  15. 15         System.out.println(money1);
  16. 16         int total=(int) (money1*100);
  17. 17         int rest=total-n;
  18. 18         int restNum=n;//剩余红包个数
  19. 19         int[] luckMoney=new int[n];
  20. 20         Random r = new Random();
  21. 21         for (int i = 0; i < luckMoney.length; i++) {
  22. 22             if (i==luckMoney.length-1){
  23. 23                 luckMoney[luckMoney.length-1]=1+rest;
  24. 24                 break;
  25. 25             }
  26. 26             if (rest>0){
  27. 27                 int temp=r.nextInt(rest*2/restNum+1);//修改处
  28. 28                 restNum--;
  29. 29                 luckMoney[i]=1+temp;
  30. 30                 rest-=temp;
  31. 31             }else {
  32. 32                 luckMoney[i]=1;
  33. 33             }
  34. 34         }
  35. 35         BigDecimal[] luckMoney1=new BigDecimal[n];
  36. 36         BigDecimal sum = new BigDecimal("0");
  37. 37         for (int i = 0; i < luckMoney.length; i++) {
  38. 38             BigDecimal a = new BigDecimal(""+luckMoney[i]);
  39. 39             BigDecimal b = new BigDecimal("100");
  40. 40             luckMoney1[i]= a.divide(b,2,BigDecimal.ROUND_HALF_UP);
  41. 41             sum=sum.add(luckMoney1[i]);
  42. 42         }
  43. 43         System.out.println(sum);
  44. 44         return luckMoney1;
  45. 45     }
  46. 46 }
复制代码
运行结果:
  1. [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



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4