将一个整数S随机拆分为N个在min~max之间的整数之和,并将分配结果存储到数组K中...

这两天做一个程序需要将金额数值按照可选区间进行自动分配,考虑了许久,采用随机数的方法编写算法,代码如下,复制即可测试.
代码虽不是完美,但足以应付小程序.若有更好的方法,欢迎指点!

package core.util;

import java.util.Random;

public class NumberRandDivideUtils {
	/**
	 * 将一个整数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 int min = 5; int max = 6; int summary =20;  
	 * @MODIFY 缩减分配与叠加分配共用后完美解决
	 */
	public static int[] randDivide(int min, int max, int summary) {
		int maxl = summary % min == 0 ? summary / min : summary / min + 1;
		int[] k = new int[maxl];
		// l:用来记录数组k中存储值的最后索引
		int l = 0;
		int total = 0;
		if (min == max) {// 如果两数相等,则常数
			if (summary % min == 0) {
				for (int i = 0; i < k.length; i++) {
					k[i] = min;
				}
			}
		} else {
			Random rand = new Random();
			int remainder;
			for (int i = 0; i < k.length; i++) {
				// 剩余数
				remainder = summary - total;
				// 如果剩余数在min与max之间,则跳出去直接设置k[++l]为余数
				if (remainder >= min && remainder <= max) {
					k[i] = remainder;
					break;
				} else if (remainder < min) {
					// 数组最小长度
					int minl = summary % max == 0 ? summary / max : summary / max + 1;
					// 如果i<最小数组长度,则缩减分配
					if (i < minl) {
						k[i] = remainder;
						l = i;
						randDivideLessenFiller(summary, min, k, l);
						break;
					} else {// 如果i>=最小数组长度,做叠加分配
						randDivideRemainder(summary, max, k, l, remainder);
						break;
					}
				}
				// 产生一个在min与max之间的随机数
				int rd = rand.nextInt(max - min + 1) + min;
				k[i] = rd;
				total += rd;
				l = i;
			}
		}
		// 校验数组中的和不等于summary则返回0
		int t = 0;
		for (int i = 0; i < k.length; i++) {
			if(k[i]<min||k[i]>max)
				break;
			t += k[i];
		}
		if (t != summary) {
			return null;
		}
		
		return k;
	}

	private static void randDivideLessenFiller(int summary, int min, int[] k, int l) {
		if (summary / (l + 1) < min)
			return;
		Random rand = new Random();
		// 最小值与平均数之间的一个随机数
		int rv = rand.nextInt(summary / (l + 1) - min + 1) + min;
		int r = rv - k[l];
		int j = 0;
		while (r > 0 && j < 1000) {
			int i = rand.nextInt(l);
			if (k[i] - r >= min) {
				k[i] -= r;
				k[l] += r;
				break;
			}
			int _r = rand.nextInt(r) + 1;
			if (k[i] - _r >= min) {
				k[i] -= _r;
				k[l] += _r;
				r -= _r;
			}
			j++;
		}
	}

	/**
	 * l:数组最后的长度 r:余数 d:控制随机分配深度,j值一般达不到1000,防止无解导致栈溢出
	 */
	private static void randDivideRemainder(int summary, int max, int[] k, int l, int r) {
		if (summary / (l + 1) > max)
			return;
		Random rand = new Random();
		int j = 0;
		while (r > 0 && j < 1000) {
			int i = rand.nextInt(l);
			if (k[i] + r <= max) {
				k[i] = k[i] + r;
				break;
			}
			int _tempMax = rand.nextInt(max - summary / (l + 1) + 1) + summary / (l + 1);
			for (int t = 0; t <= l; t++) {
				if (k[t] < _tempMax) {
					// 最大数为程序要求的区间最大数-k[i],即空间与余数作比较
					int _max = (_tempMax - k[t]) < r ? (_tempMax - k[t]) : r;
					if (_max == 0)
						continue;
					// 这里仍用随机数,而不是自动填补的原因是,不让数字整齐
					int rn = rand.nextInt(_max) + 1;
					k[t] += rn;
					r -= rn;
				}
			}
			j++;
		}
	}
}

 

转载于:https://my.oschina.net/u/198423/blog/531892

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是给出的代码,可以采用分治法求一个整数序列的最大值和最小值: ``` #include<iostream> #include<algorithm> using namespace std; // 分治法求最大值 int findMax(int arr[], int left, int right) { if (left == right) { // 长度为1时直接返回 return arr[left]; } else if (left + 1 == right) { // 长度为2时比较 return max(arr[left], arr[right]); } else { // 长度大于2时继续递归 int mid = (left + right) / 2; // 求间位置 int leftMax = findMax(arr, left, mid); // 递归求左边的最大值 int rightMax = findMax(arr, mid + 1, right); // 递归求右边的最大值 return max(leftMax, rightMax); // 取两者最大值 } } // 分治法求最小值 int findMin(int arr[], int left, int right) { if (left == right) { // 长度为1时直接返回 return arr[left]; } else if (left + 1 == right) { // 长度为2时比较 return min(arr[left], arr[right]); } else { // 长度大于2时继续递归 int mid = (left + right) / 2; // 求间位置 int leftMin = findMin(arr, left, mid); // 递归求左边的最小值 int rightMin = findMin(arr, mid + 1, right); // 递归求右边的最小值 return min(leftMin, rightMin); // 取两者最小值 } } int main() { int arr[] = {3, 1, 4, 2, 5}; // 测试用例 int n = sizeof(arr) / sizeof(arr[0]); // 数组长度 cout << "最大值为:" << findMax(arr, 0, n - 1) << endl; cout << "最小值为:" << findMin(arr, 0, n - 1) << endl; return 0; } ``` 以上代码,采用了递归的方法,将序列不断拆分为左右两个子序列,直到序列的长度为1或2,然后分别求出左右子序列的最大(小)值,最后比较两者,得到序列的最大(小)值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值