首先生成n
随机数x[i]
,将它们相加,然后除以总budget
和,您将得到k
。然后分配k*x[i]
给每个数组元素。它很简单而且 O(n)。
如果您希望每个元素中至少有min
值,您可以通过min
(或使用)填充所有元素并在开始上述算法之前k*x[i] + min
分包n*min
来修改上述算法。budget
如果您需要使用整数,您可以使用 real valuek
和 rounding来解决问题k*x[i]
。然后,您必须跟踪累积舍入误差,如果计算值达到整个单位,则从计算值中添加或减去累积误差。您还必须将剩余值分配给最后一个元素才能达到整体budget
。
PS:请注意,此算法可以在纯函数式语言中轻松使用。这就是为什么我喜欢这一系列算法为每个成员生成随机数然后进行一些处理的原因。Erlang 中的实现示例:
-module(budget).
-export([distribute/2, distribute/3]).
distribute(Budget, N) ->
distribute(Budget, N, 0).
distribute(Budget, N, Min) when
is_integer(Budget), is_integer(N), N > 0,
is_integer(Min), Min >= 0, Budget >= N*Min ->
Xs = [random:uniform() || _ <- lists:seq(1,N) ],
Rest = Budget - N*Min,
K = Rest / lists:sum(Xs),
F = fun(X, {Bgt, Err, Acc}) ->
Y = X*K + Err,
Z = round(Y),
{Bgt - Z, Y - Z, [Z + Min | Acc]}
end,
{Bgt, _, T} = lists:foldl(F, {Rest, 0.0, []}, tl(Xs)),
[Bgt + Min | T].
C ++中的相同算法(??我不知道。)
private int[] distribute(int budget, int n, int min) {
int[] subBudgets = new int[n];
double[] rands = new double[n];
double k, err = 0, sum = 0;
budget -= n * min;
for (int i = 0; i < n; i++) {
rands[i] = random.nextDouble();
sum += rands[i];
}
k = (double)budget/sum;
for (int i = 1; i < n; i++) {
double y = k*rands[i] + err;
int z = floor(y+0.5);
subBudgets[i] = min + z;
budget -= z;
err = y - z;
}
subBudgets[0] = min + budget;
return subBudgets;
}