java实现微信红包分配算法
红包算法分析
有人认为,抢红包的额度是从0.01到剩余平均值*N(N是一个系数,决定最大的红包值)之间,比如一共发了10块钱,发了10个红包:第一个人可以拿到(0.01~1*N)之间的一个红包值,当然为了确保所有人至少有1分钱拿,不能前几个人就把钱拿光了,因此需要有一个判断算法。举个例子,如果每个人都拿了自己的最大值:
package 红包分配; public class test { public static void main(String[] args){ float num=10,N=1.9f; int people=10; for(int i=0;i<10;i++) { System.out.println("the number"+people+"can get "+num/people*N); num=num-num/people*N; people--; } System.out.println("there remain"+num); } }
运行结果如下:
the number10can get 1.9 the number9can get 1.71 the number8can get 1.5176251 the number7can get 1.3225019 the number6can get 1.1241267 the number5can get 0.9217838 the number4can get 0.71438247 the number3can get 0.5000677 the number2can get 0.2750373 the number1can get 0.027503723 there remain-0.01302808
最终剩余的钱数为负数,不符合要求,所以说基数的选取是非常重要的。
设置金额的限额
private static final float MINMONEY = 0.01f; private static final float MAXMONEY = 200f;
红包的最小额度是0.01元,最大额度是200元。
判断金额是否合法
如果金额超过限额,就出错了
private boolean isRight(float money,int count) { double avg = money/count; if(avg<MINMONEY){ return false; } else if(avg>MAXMONEY) { return false; } return true; }
随机产生红包
用随机方法产生一个在最大值和最小值之间的一个红包,并判断该红包是否合法,是否在产生这个红包之后红包金额变成负数。另外,在这次产生红包值较小时,下一次就产生一个大一点的红包。
private float randomRedPacket(float money,float mins,float maxs,int count) { if(count==1) { return (float)(Math.round(money*100))/100; } if(mins == maxs) { return mins;//如果最大值和最小值一样,就返回mins } float max = maxs>money?money:maxs; float one = ((float)Math.random()*(max-mins)+mins); one = (float)(Math.round(one*100))/100; float moneyOther = money - one; if(isRight(moneyOther,count-1)) { return one; } else{ //重新分配 float avg = moneyOther / (count-1); if(avg<MINMONEY) { return randomRedPacket(money,mins,one,count); }else if(avg>MAXMONEY) { return randomRedPacket(money,one,maxs,count); } } return one; }
实现红包分配
为了避免一个红包占用大量的资金,设定非最后一个红包的最大金额,可以设置为平均值的N倍,基于前面的方法就可以实现红包的分配了。
private static final float TIMES = 2.1f; public List<Integer> splitRedPackets(float money,int count) { if(!isRight(money,count)) { return null; } List<Float> list = new ArrayList<Float>(); float max = (float)(money*TIMES/count); max = max>MAXMONEY?MAXMONEY:max; for(int i=0;i<count;i++) { float one = randomRedPacket(money,MINMONEY,max,count-i); list.add(one); money-=one; } return list; }
private static final float TIMES = 2.1f; public List<Integer> splitRedPackets(float money,int count) { if(!isRight(money,count)) { return null; } List<Float> list = new ArrayList<Float>(); float max = (float)(money*TIMES/count); max = max>MAXMONEY?MAXMONEY:max; for(int i=0;i<count;i++) { float one = randomRedPacket(money,MINMONEY,max,count-i); list.add(one); money-=one; } return list; }
编写主函数
public static void main(String[] args) { RedPacketUtil util = new RedPacketUtil(); System.out.println(util.splitRedPackets(200, 100)); }
anytime you feel the pain.hey,refrain.don't carry the world upon your shoulders