这两天做一个程序需要将金额数值按照可选区间进行自动分配,考虑了许久,采用随机数的方法编写算法,代码如下,复制即可测试.
代码虽不是完美,但足以应付小程序.若有更好的方法,欢迎指点!
public class Main { /** * @param args */ public static void main(String[] args) { testRandDivide(); } public static void testRandDivide() { long t1 = System.currentTimeMillis(); int success = 0; int testTotal = 1000; for (int j = 0; j < testTotal; j++) { int min = 5; int max = 8; int summary = 12; // 创建一个用来存储结果数据的数组 int[] k = new int[summary / min]; // 数组中有效数据长度 int s = randDivide(min, max, summary, k); if (s > 0) { System.out.println("分配成功,可以使用数组k[s]了."); success++; } else System.err.println("本次分配未成功,请检查分配参数或重试一次!"); } System.out.println("分配成功率:" + success * 100.0 / testTotal + "%"); System.out.println("time:" + (System.currentTimeMillis() - t1) + "ms."); } /** * 将一个整数summary随机拆分为N个在min~max之间的整数之和,并将分配结果存储到数组k中 * 注意:min~max之间差越大,则越容易随机分配,反之,差越小,分配越困难,甚至无解 * eg:min:5,max:8,summary:20,可以看出5 * +5+5+5+5=20,6+6+8=20,7+7+6=20,5+7+8=20,但使用随机数5~8,可能 * 第一次取到8,第2次也取到8,接下来无论怎么分配,也不可能为20 */ private static int randDivide(int min, int max, int summary, int[] k) { Random rand = new Random(); int s = 0; int total = 0; for (int i = 0; i < summary / min; i++) { // 产生一个在min与max之间的随机数 int result = rand.nextInt(max - min + 1) + min; // 剩余数 int remainder = summary - total; // 如果剩余数在min与max之间,则跳出 if (remainder >= min && remainder <= max) break; if ((remainder - result) > 0) { k[i] = result; s = i; total += result; } } if ((summary - total) >= min && (summary - total) <= max) { s++; k[s] = (summary - total); } if ((summary - total) < min) { int r = (summary - total); // 使用随机数划分 randDivideRemainder(max, k, s, r, 1); } // 校验 int t = 0; for (int i = 0; i <= s; i++) { t += k[i]; } if (t != summary) { s = 0; } return s; } /** * d:控制随机分配深度,防止无解导致栈溢出 */ private static void randDivideRemainder(int max, int[] k, int s, int r, int d) { Random rand = new Random(); for (int i = 0; i <= s; i++) { int _max = (max - k[i]) < r ? (max - k[i]) : r; if (_max == 0) continue; int result = rand.nextInt(_max - 1 + 1) + 1; k[i] = k[i] + result; r = r - result; if (r == 0) break; } if (r > 0 && d <= 100) { randDivideRemainder(max, k, s, r, ++d); } } }