how do I get the Nth arrangement out of all possible combinations of arranging 4 indistinguishable balls in 3 distinct buckets. if Bl
= number of balls
and Bk
= number of buckets
e.g. for Bl = 4, Bk = 3 the possible arrangements are :
004
,013
,022
,031
,040
,103
,112
,121
,130
,202
,211
,220
,301
,310
,400
.
the first arrangement(N=0) is 004
(i.e. bucket 1 = 0 balls, bucket 2 = 0 balls, bucket 3 = 4 balls) and the last(N=14) is 400
. so say I have 103
N would be equal to 5. I want to be able to do
int Bl=4,Bk=3;
getN(004,Bl,Bk);// which should be = 0
getNthTerm(8,Bl,Bk);// which should be = 130
P.S: max number of terms for the sequence is (Bl+Bk-1)C(Bk-1) where C is the combinatorics/combination operator.
Obtained from
stars and bars
As far as I know, there is no faster way of doing this than combinatorial decomposition which takes roughly O(Bl) time.
We simply compute the number of balls which go into the each bucket for the selected index, working one bucket at a time. For each possible assignment to the bucket we compute the number of possible arrangements of the remaining balls and buckets. If the index is less than that number, we select that arrangement; otherwise we put one more ball in the bucket and subtract the number of arrangements we just skipped from the index.
Here's a C implementation. I didn't include the binom
function in the implementation below. It's usually best to precompute the binomial coefficients over the range of values you are interested in, since there won't normally be too many. It is easy to do the computation incrementally but it requires a multiplication and a division at each step; while that doesn't affect the asymptotic complexity, it makes the inner loop much slower (because of the divide) and increases the risk of overflow (because of the multiply).
/* 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;
}
There are some interesting bijections that can be made. Finally, we can use ranking and unranking methods for the regular k-combinations, which are more common knowledge.
A bijection from the number of balls in each bucket to the ordered multiset of choices of buckets; for example: [3, 1, 0] --> [1, 1, 1, 2]
(three choices of 1 and one choice of 2).
A bijection from the k-subsets of {1...n}
(with repetition) to k-subsets of {1...n + k − 1}
(without repetition) by mapping {c_0, c_1...c_(k−1)}
to {c_0, c_(1+1), c_(2+2)...c_(k−1+k−1)}
(see here).
Here's some python code:
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)
Output:
"""
[0, 0, 4] --> [3, 3, 3, 3] --> [3, 4, 5, 6]
[0, 1, 3] --> [2, 3, 3, 3] --> [2, 4, 5, 6]
[0, 2, 2] --> [2, 2, 3, 3] --> [2, 3, 5, 6]
[0, 3, 1] --> [2, 2, 2, 3] --> [2, 3, 4, 6]
[0, 4, 0] --> [2, 2, 2, 2] --> [2, 3, 4, 5]
[1, 0, 3] --> [1, 3, 3, 3] --> [1, 4, 5, 6]
[1, 1, 2] --> [1, 2, 3, 3] --> [1, 3, 5, 6]
[1, 2, 1] --> [1, 2, 2, 3] --> [1, 3, 4, 6]
[1, 3, 0] --> [1, 2, 2, 2] --> [1, 3, 4, 5]
[2, 0, 2] --> [1, 1, 3, 3] --> [1, 2, 5, 6]
[2, 1, 1] --> [1, 1, 2, 3] --> [1, 2, 4, 6]
[2, 2, 0] --> [1, 1, 2, 2] --> [1, 2, 4, 5]
[3, 0, 1] --> [1, 1, 1, 3] --> [1, 2, 3, 6]
[3, 1, 0] --> [1, 1, 1, 2] --> [1, 2, 3, 5]
[4, 0, 0] --> [1, 1, 1, 1] --> [1, 2, 3, 4]
"""
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With