如何从在3个不同的桶中排列4个无法区分的球的所有可能组合中获得 Nth 布置。如果Bl
= number of balls
和Bk
= number of buckets
,例如对于 Bl = 4, Bk = 3,可能的安排是:
004
,013
,022
,031
,040
,103
,112
,121
,130
,202
,211
,220
,301
,310
,400
。
第一个排列( N = 0 )是004
(即存储桶1 = 0球,存储桶2 = 0球,存储桶3 = 4个球),最后一个( N = 14 )是400
。因此说我有103
N 等于 5 。我希望能够做到
int Bl=4,Bk=3;
getN(004,Bl,Bk);// which should be = 0
getNthTerm(8,Bl,Bk);// which should be = 130
PS:该序列的最大术语数是(Bl + Bk-1)C(Bk-1),其中 C 是组合/组合运算符。
Obtained from
stars and bars
答案 0 :(得分:2)
据我所知,没有比完成大约O(Bl)时间的组合分解更快的方法了。
我们只需计算所选索引进入每个存储桶的球数,一次工作一个存储桶即可。对于铲斗的每个可能分配,我们计算剩余的球和铲斗的可能布置数量。如果索引小于该数字,则选择该排列;如果索引小于该数字,则选择该排列。否则,我们会再增加一个球,然后从索引中减去刚跳过的安排数。
这是一个C实现。我没有在下面的实现中包含binom
函数。通常最好在您感兴趣的值范围内预先计算二项式系数,因为通常不会有太多。增量计算很容易,但是每一步都需要相乘和除法。尽管这不会影响渐近复杂度,但会使内循环变慢(由于除法),并增加了溢出的风险(由于乘法)。
/* Computes arrangement corresponding to index.
* Returns 0 if index is out of range.
*/
int get_nth(long index, int buckets, int balls, int result[buckets]) {
int i = 0;
memset(result, 0, buckets * sizeof *result);
--buckets;
while (balls && buckets) {
long count = binom(buckets + balls - 1, buckets - 1);
if (index < count) { --buckets; ++i; }
else { ++result[i]; --balls; index -= count; }
}
if (balls) result[i] = balls;
return index == 0;
}
答案 1 :(得分:1)
可以做出一些有趣的双射。最后,我们可以对常规k组合使用排名和取消排名方法,这是更常见的知识。
从每个铲斗的球数到铲斗选择的有序多重集的双射;例如:php artisan storage:link
(1的三个选择和2的一个选择)。
通过将[3, 1, 0] --> [1, 1, 1, 2]
映射到{1...n}
,从{1...n + k − 1}
的k个子集(有重复)到{c_0, c_1...c_(k−1)}
的k个子集(无重复)的双射(请参阅here)。
这是一些python代码:
{c_0, c_(1+1), c_(2+2)...c_(k−1+k−1)}
输出:
from itertools import combinations_with_replacement
def toTokens(C):
return map(lambda x: int(x), list(C))
def compositionToChoice(tokens):
result = []
for i, t in enumerate(tokens):
result = result + [i + 1] * t
return result
def bijection(C):
result = []
k = 0
for i, _c in enumerate(C):
result.append(C[i] + k)
k = k + 1
return result
compositions = ['004','013','022','031','040','103','112',
'121','130','202','211','220','301','310','400']
for c in compositions:
tokens = toTokens(c)
choices = compositionToChoice(tokens)
combination = bijection(choices)
print "%s --> %s --> %s" % (tokens, choices, combination)