是否有一种有效的算法将一个数字分成N
个小部分,以便数字之和等于原始数字,并具有最小基数?例如,如果我想将 50 分成 7 个小节,并且最小基数为 2,我可以执行 10,5,8,2,3,5,17
(以及任何其他组合数)。我想将数字保留为整数,并且相对随机,但我不确定如何有效地生成总和等于原始值且不包含低于给定最小值的数字。有什么建议吗?
编辑-只是为了复制/粘贴我的评论,整数不必是唯一的,但我想避免每次都使用相同的大小(例如 50 分成 10 个相同大小)。
Is there an efficient algorithm to split up a number into N
subsections so that the sum of the numbers adds up to the original, with a base minimum? For example, if I want to split 50 into 7 subsections, and have a base minimum of 2, I could do 10,5,8,2,3,5,17
(as well as any other number of combinations). I'd like to keep the numbers as integers, and relatively random but I'm not sure how to efficiently generate numbers that sum up to the original and don't include numbers lower than the given minimum. Any suggestions?
EDIT - Just to copy/paste my comment, the integers don't have to be unique, but I want to avoid equal sizes for all of them (e.g. 50 split into 10 equal sizes) everytime.
发布评论
评论(10)
这是一个算法:
N
除以m
,其中N
是您的数字,m
是小节的数量。N
。此时,如果N
为 50,m
为 7,则有 8, 7, 7, 7, 7, 7, 7m-1
,步进 2,并在-(currentValue-base)
和currentValue-base
之间添加一个随机数。将该数字的倒数添加到其相邻的存储桶中。如果您有奇数个存储桶,则在最后一个存储桶上,不要将该数字的倒数添加到其相邻的存储桶中,而是以类似于上面的步骤 2 和 3 的分布式方式将其添加到所有其他存储桶中。表现:
第 1 步的时间为
O(1)
,步骤 2、3 和 4 的时间为O(m)
,因此总体来说为O(m)
。Here's an algorithm:
N
bym
whereN
is your number andm
is the number of subsections.N
. At this point ifN
was 50 andm
was 7, you'd have 8, 7, 7, 7, 7, 7, 7m-1
, stepping by 2, and add a random number between-(currentValue-base)
andcurrentValue-base
. Add the inverse of that number to its neighboring bucket. If you have an odd number of buckets, then on the last bucket instead of adding the inverse of that number to its neighboring bucket, add it to all of the other buckets in a distributed manner similar to steps 2 and 3 above.Performance:
Step 1 is
O(1)
, Steps 2, 3, and 4 areO(m)
, so overall it'sO(m)
.您可以通过从数字中减去最小乘以 N、生成 N 个小节并添加最小值来轻松消除最小值的要求。在您的示例中,问题简化为将 36 拆分为 7 个整数,并且您给出了拆分 8,3,6,0,1,3,15。
解决方案的其余部分取决于“相对随机”要求的性质。对于一些最小的随机性,请考虑在 0 和未分割部分之间顺序选择数字(例如,首先在 0 和 36 之间,获得 8,然后在 0 和 28 之间,获得 3,依此类推 7 次)。如果这还不够,您需要首先定义随机性。
You can easily remove the requirement of a minimum by subtracting minimum times N from the number, generating the N subsections and adding the minimum. In your example, the problem reduces to splitting 36 into 7 integers, and you have given the split 8,3,6,0,1,3,15.
The rest of the solution depends on the nature of the "relatively random" requirement. For some minimal randomness, consider choosing numbers sequentially between 0 and the unsplitted part (e.g. between 0 and 36 first, gaining 8, then between 0 and 28, gaining 3, and so on 7 times). If that doesn't suffice, you'll need to define randomness first.
这是一个伪随机解决方案[请注意,解决方案可能有偏差,但相对随机]。
对于第 1 部分,例如:对于
n=50, k = 7
,您将设置:x1=x2=...=x6=7,x7=8
,用线性时间计算和填充这样的列表没有问题。性能:
如上所述,step1 的复杂度为 O(k)。
步骤2,简单的实现是O(k^2),但是由于你均匀地分配
temp-xi
的结果,所以有O(k)的实现,只需要存储和修改增量。步骤 3 只是一个简单的洗牌,O(k)
总体性能:O(k),并带有步骤 2 的增量实现
here is a pseudo random solution [note that solution might be biased, but will be relatively random].
regarding part 1, for example: for
n=50, k = 7
, you will set:x1=x2=...=x6=7,x7=8
, no problem to compute and populate such a list with linear time.Performance:
As said, step1 is O(k).
Step2, with naive implementation is O(k^2), but since you distribute result of
temp-xi
evenly, there is O(k) implementation, with just storing and modifying delta.Step3 is just a simple shuffle, O(k)
Overall performance: O(k) with delta implemntation of step2
好吧,我想出了一些“只是为了好玩”的东西。
它从
最小值
逐渐增加到数字
,并使用取模和随机的方式用N
部分填充数组。请参阅此处的 jsFiddle。
如果此数字的部分太多,它将无法按预期工作。 (即
数字)
Well I've come up with something "just for fun".
It goes incrementally from
minimum
tonumber
and populates an array withN
sections using modulo and random.See the jsFiddle here.
It won't work as expected if there are too many sections for this number. (ie
number < N(N+1)/2
)下面是创建所请求的数字重新分区的代码的 Java 示例。这是递归方法,我们将问题分解为 2 个子问题:如果我们想将一个数字分解为 n 个篮子中的分量之和,那么我们尝试一次考虑一个子数字,并为每个子问题委托找出答案剩余分解到 (n-1) 个篮子之间重新分配的递归调用。
处理特定子数时(在 for 循环中)会考虑请求的阈值。
Here is a java example of code creating the requested repartition of numbers. It is recursive approach, we decompose the problem into 2 subproblems : if we want to decompose a number in to a sum of components amongst n baskets, then we try to consider a subnumber at a time, and for each of them delegate the finding out of the remaining decomposition to the recursive call for the repartition amongst (n-1) baskets.
The requested threshold is considered when processing a particular subnumber (in the for loop).
现在,如果您希望最小数字为 2 以外的其他数字,请将其更改为提供的任何值 number_of_subsections * min_random_number_desired <= number。
Now if you want minimum number to be something else besides 2, change it to any value provided number_of_subsections * min_random_number_desired <= number.
让我用Python 来写它。
假设您有 50 个元素要分成 7 个框,并且每个框内至少需要两个元素。
我们默认在每个框中放置 s 个元素,因此剩下 N 个元素。
我们随机抽取 m 个数字,对它们进行排序,然后在后面附加 N。这就像在一本 N 页的书中随机插入 m 个书签。
连续书签之间的页数是随机的。 (我们有 s,以便我们确定每个盒子至少有 s 个元素)
完成!
Let me write it in Python.
Let's say that you have 50 elements to split into 7 boxes and you want at least two inside each of them.
We put s elements by default in each box so we are left with N elements.
We draw m random numbers, sort them, append N on the back. This is like inserting randomly m bookmarks in a book of N pages.
The number of pages between consecutive bookmarks is random. (We had s so that we are sure that each box has at least s elements)
Done!
这是一个 Ruby 实现。
Here is a Ruby implementation.
我知道已经有很长一段时间了,但我想添加我的答案来帮助某人,这里是我使用递归的代码
这里 n 等于 10 但你可以像询问用户一样,通过使用声明 a 的大小新运营商!
I know there`s been a long time but i would like to add my answer to help someone here is my code using recursion
Here n is equal to 10 but u could make it like asking the user,declare the size of a by using the new operator !
我正在做类似的事情,这就是我的想法。
您可以在每一步使用一些计算以 O(N-1) 的速度完成此操作。首先,您在每个点的最小数和最大数之间选择一个随机数。对于每个点,最大数量是通过从剩余余额中减去 (Min_Number * Remaining_Spots) 来计算的。
例如:对于第一个位置,您选择一个 2 到 38 之间的数字。您可以通过从 50 中减去 (7-1)*2 来得到这个数字。即 50 - 12 = 38。
一旦您选择了一个数字,假设是 19,那么对于下一个位置的范围是 2-21。即 50-19-(5*2) = 21..
..等等。
这是代码片段:
这是示例输出:
这是 jsFiddle:
http://jsfiddle.net/wj81kvsc/6/
I was working on something similar and here is what I came up with.
You can do this in O(N-1) using some calculations at each step. You begin by picking a random number between the minimum number and max number for each spot. For each spot, max number is calculated by subtracting (Min_Number * Remaining_Spots) from the Remaining Balance.
For example: for the first spot you pick a number between 2 and 38. You get this by subtracting (7-1)*2 from 50. i.e. 50 - 12 = 38.
Once you pick a number, let's say 19, then for the next spot the range is 2-21. i.e. 50-19-(5*2) = 21..
..and so on.
Here is the code snippet:
Here is the sample output:
Here is the jsFiddle:
http://jsfiddle.net/wj81kvsc/6/