红包生成算法
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by fei-ke on 2015/6/18.
*/
public class RedPackAmountGenerator {
private int mFloor; //下限
private int mCeiling; //上限
private int mCount; //数量
private int mTotal; //金额
private int mCurrent; //当前游标
/**
* @param total 金额
* @param count 总个数(为0时自动根据上下限估算个数)
* @param floor 下限
* @param ceiling 上限
* @param floatRange 浮动范围(在平均值左右浮动的范围)
*/
public RedPackAmountGenerator(int total, int count, int floor, int ceiling, float floatRange) {
this.mTotal = total;
this.mCount = count;
int avg;
if (count != 0) {
avg = total / count;
} else {
avg = (floor + ceiling) / 2;
this.mCount = total / avg;
}
this.mFloor = Math.max(floor, (int) (avg - avg * floatRange));
this.mCeiling = Math.min(ceiling, (int) (avg + avg * floatRange));
this.mCurrent = 1;
}
/**
* 产生下一个随机数
*
* @param current 当前第几个人(从1开始)
* @param leftAmount 剩余金额
* @return
*/
public int next(int current, int leftAmount) {
this.mCurrent = current;
this.mTotal = leftAmount;
Range range = curRange();
if (range.ceiling == range.floor) return range.ceiling;
Random r = new Random();
//nextInt范围为左闭右开区间,右值+1
int next = r.nextInt(range.ceiling + 1 - range.floor) + range.floor;
this.mTotal -= next;
this.mCurrent++;
return next;
}
/**
* 检查金额人数上下限和浮动范围是否合理
*
* @return
*/
public boolean isOK() {
return mTotal >= mCount * mFloor && mTotal <= mCount * mCeiling;
}
/**
* 产生下一个随机数,当前人数和剩余金额由内部记录
*
* @return
*/
public int next() {
return next(mCurrent, mTotal);
}
/**
* 一次性生成所有随机数
*
* @return
*/
public List all() {
ArrayList list = new ArrayList();
for (int i = mCurrent; i <= mCount; i++) {
int next = next();
list.add(next);
}
return list;
}
/**
* 计算本次随机的范围
*/
private Range curRange() {
//本次生成之后剩余个数
int leftCount = mCount - mCurrent;
if (leftCount == 0) {
return new Range(mTotal, mTotal);
}
//需要剩下最少的值
int minLeft = leftCount * this.mFloor;
//需要剩下最大的值
int maxLeft = Math.min(leftCount * this.mCeiling, mTotal - this.mFloor);
//本次随机的下限:max(本次可取最小值,基本下限,浮动范围下限)
int rangeFloor = Math.max(mTotal - maxLeft, this.mFloor);
//本次随机的上限:min(基本上限,本次可取最大值,浮动范围上限)
int rangeCeiling = Math.min(this.mCeiling, mTotal - minLeft);
return new Range(rangeFloor, rangeCeiling);
}
/* static int min(int... nums) {
int min = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] < min) {
min = nums[i];
}
}
return min;
}
static int max(int... nums) {
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] > max) {
max = nums[i];
}
}
return max;
}*/
/**
* 随机范围辅助类
*/
private static class Range {
int floor; //下限
int ceiling; //上限
public Range(int floor, int ceiling) {
this.floor = floor;
this.ceiling = ceiling;
}
}
public static void main(String[] args) {
int amount = 500;
int person = 40;
RedPackAmountGenerator generator = new RedPackAmountGenerator(amount, person, 1, 200, 0.8f);
System.out.println("amount:" + amount + ", person:" + person);
if (!generator.isOK()) {
System.out.println("不合理");
return;
}
System.out.println(generator.all());
}
}