金額隨機分配算法(修改版)
阿新 • • 發佈:2018-02-09
算法 sca final 是否 打印 util sin sys next
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; /** * 金額隨機分配算法 * @author kwf * @since 2018-2-9 11:03:59 */ public class Main { //需要設置的參數 private static final double MIN_MONEY = 0.1; //用戶獲得的最小金額 private static final double MAX_MONEY = 0; //用戶獲得的最大金額(可能存在誤差。主要用於計算倍數,值為0則使用默認倍數) private static final double TOTAL_MONEY = 888;//總金額 private static final int TOTAL_COUNT = 3000;//總份數 private static final boolean IS_UPSET = true;//結果是否需要打亂 private static double times = 10;//倍數(用戶獲得的最大金額=當前平均值*倍數,當前平均值=剩余金額/剩余份數)(若最大金額不為0則會被重新賦值) private staticdouble AVG_SCALE = 0.8;//趨於均值的比例 private static double AVG_FLOAT_SCALE = 0.5;//均值上下浮動的比例 private static double avgMoney = TOTAL_MONEY / TOTAL_COUNT;//平均值 private static int avgCount = (int)Math.floor(TOTAL_COUNT * AVG_SCALE);//趨於均值的份數 private static double randomCount = TOTAL_COUNT - avgCount;//隨機分配份數 private static double leftMoney = TOTAL_MONEY; //剩余金額 private static int leftCount = TOTAL_COUNT;//剩余份數 private static double avgTotal = 0;//均值列表總值 private static double randomTotal = 0;//隨機列表總值 private static int runCount = 0;//運行次數 private static int minCount = 0;//算法中獲得的最小金額的個數 private static int avgBottomCount = 0;//均值以下的個數 private static double maxValue, minValue; //算法中獲得的最大值和最小值 private static List<Double> list = new ArrayList<>(); //用於存儲金額列表 private static int treeTime = 1;//遞歸次數,超過10次直接返回最小值,防止遞歸層數過深導致的棧溢出 public static void main(String[] args) { System.out.println("倍數為" + setTimes() + ",平均值為" + avgMoney); if(!isRight(TOTAL_MONEY, TOTAL_COUNT)) { //如果設置金額和份數不合法則報錯 initAllAvgList(); } else{ initAvgList(); initRandomList(); } if(IS_UPSET) { System.out.println("打亂前:" + list); //打印打亂前的金額列表 Collections.shuffle(list);//打亂列表 System.out.println("打亂後:" + list); //打印打亂後的金額列表 } else{ System.out.println(list); //打印金額列表 } System.out.println("均值總額為" + Math.round(avgTotal) + ",隨機總額為" + Math.round(randomTotal)); System.out.println("算法運行了" + runCount + "次"); //打印金額列表 maxValue = minValue = list.get(0); for(double value:list) { maxValue = value > maxValue ? value : maxValue; minValue = value < minValue ? value : minValue; } System.out.println("最大值為" + maxValue + ",最小值為" + minValue); System.out.println("小於平均值的個數為" + avgBottomCount); System.out.println("最小金額的個數為" + minCount); } /** * 填充真實均值列表 */ private static void initAllAvgList() { for(int i = 0; i < TOTAL_COUNT; i++) { double money = Math.floor(avgMoney * 100) / 100; list.add(money); avgTotal += money; if(money < avgMoney) avgBottomCount++; if(Double.doubleToLongBits(money) == Double.doubleToLongBits(MIN_MONEY)) minCount++; } } /** * 填充浮動均值列表 */ private static void initAvgList() { for(int i = 0; i < avgCount; i++) { double money = getAvgMoney(); list.add(money); avgTotal += money; if(money < avgMoney) avgBottomCount++; if(Double.doubleToLongBits(money) == Double.doubleToLongBits(MIN_MONEY)) minCount++; } } /** * 填充隨機列表 */ private static void initRandomList() { for(int i = 0; i < randomCount; i++) { double money = getRandomMoney(); list.add(money); randomTotal += money; if(money < avgMoney) avgBottomCount++; if(Double.doubleToLongBits(money) == Double.doubleToLongBits(MIN_MONEY)) minCount++; } } /** * 均值上下浮動算法 * @return 誤差均值(均值+均值*浮動比例) */ private static double getAvgMoney() { runCount++; if(treeTime >= 10) { treeTime = 1; return MIN_MONEY; } if (leftCount == 1) { return (double) Math.round(leftMoney * 100) /100; } Random r = new Random(); double money = avgMoney + (r.nextDouble() * 2 -1) * AVG_FLOAT_SCALE * avgMoney; money = money <= MIN_MONEY ? MIN_MONEY : money; money = Math.floor(money * 100) / 100; if(isRight(leftMoney - money, leftCount - 1)) { treeTime = 1; leftMoney -= money; leftCount--; return money; } else {//如果不合法則遞歸調用隨機算法,直到合法 treeTime++; return getAvgMoney(); } } /** * 隨機算法 * @return 隨機金額(最小金額~當前均值*倍數) */ private static double getRandomMoney() { runCount++; if(treeTime >= 10) { treeTime = 1; return MIN_MONEY; } if (leftCount == 1) { return (double) Math.round(leftMoney * 100) /100; } Random r = new Random(); double max = leftMoney / leftCount * times; double money = r.nextDouble() * max; money = money <= MIN_MONEY ? MIN_MONEY : money; money = Math.floor(money * 100) / 100; if(isRight(leftMoney - money, leftCount - 1)) { treeTime = 1; leftMoney -= money; leftCount--; return money; } else {//如果不合法則遞歸調用隨機算法,直到合法 treeTime++; return getRandomMoney(); } } /** * 判斷金額和份數是否合法,平均值小於最小金額則視為不合法 * @param money 金額 * @param count 份數 * @return 合法性 */ private static boolean isRight(double money, int count) { return money / count >= MIN_MONEY; } /** * 設置倍數(僅當設置了最大金額才有效,否則為默認倍數) * @return 倍數 */ private static double setTimes() { if(MAX_MONEY != 0) { times = MAX_MONEY / (TOTAL_MONEY / TOTAL_COUNT); } return times; } }
金額隨機分配算法(修改版)