The algorithm you are interested in is very easy to implement. The first thing you should understand is why actually C(k, n + k - 1) = C(n - 1, n + k - 1) = (n + k - 1)! / k! / (n - 1)! formula works. Formula says that the number of ways to take k items out of n is the same as to take n-k items out of n.
Lets say your objects are balls of some color. There are n different colors numbered from 1 to n. You need to calculate the number of ways to have k balls. Imagine initially k white balls (without any color) so you need to paint them in different ways. Arrange the balls in a row. Choose some k1 ≥ 0 balls from the left to paint in color #1, next k2 ≥ 0 balls we paint in #2, and so on... We have ∑ki = k. A series of k1 balls painted in color #1 is followed by k2 of color #2, next by k3 of color #3 etc...
We can do the same painting in a slightly different way however. In order to separate ki-1- and ki-colored balls we would use delimiters. In total we should have n - 1 such delimiters to be placed among the balls. The delimiters are ordered, one that separates 1-colored and 2-colored balls should appear before another that separates 2-colored and 3-colored. If some ki = 0 then corresponding delimiters appear one by one. We have to arrange delimiters and balls in some way.
Interestingly we can imagine now that both n - 1 delimiters and k balls are just objects initially placed in a row. We have to choose either n - 1 of them to declare selected objects to be delimiters or k objects to be balls. And that's where well-known combination formula can be applied.
Example for your case:
o
- ball
.
- delimiter
a, b, c
- colors
We have:
ooo.. => aaa
oo.o. => aab
oo..o => aac
o.oo. => abb
o.o.o => abc
o..oo => acc
.ooo. => bbb
.oo.o => bbc
.o.oo => bcc
..ooo => ccc
Notice the pattern how delimiters move from right to left.
Algorithm
Now to the question of how to get the p-th arrangement. Efficient algorithm description follows. Remember that we have k balls and nd = n - 1 delimiters. We will be placing delimiters one by one first trying their rightmost positions. Consider leaving current delimiter at its current position, calculate the number of combinations to place the remaining objects to the right, let the number be some N. Compare N with p, if p is greater or equal to N then reduce p by N (p <- p - N
) and we should move current delimiter left by 1. Else if p is lower than N then we will not move current delimiter but proceed to the next one trying to move it again from the rightmost position. Note that p-th arrangement is zero-based.
Having "converted" some i-th object to j-th delimiter we have N = C(nd - j, nd + k - i) number of ways to arrange remaining k - i + j balls and nd - j delimiters.
Since we'll often refer to binomial coefficients we'd better make their precalculation.
The reverse function may be implemented accordingly. You have positions for every delimiter. Accumulate the number of ways to arrange remaining objects while moving ordinary delimiter to its place from the rightmost position.
Example:
3
balls, 2
delimiters, find 7-th
arrangement (which is bbc
or .oo.o
)
Place delimiters to the rightmost position: ooo..
. Let first delimiter be current.
Calculate N = C(1, 1) = 1, p ≥ N so we reduce p by N getting p = 6. At the same time we move current delimiter 1 pos left getting oo.o.
.
Calculate N = C(1, 2) = 2, p ≥ N, reduce p by N getting p = 6 - 2 = 4. Move getting o.oo.
.
Calculate N = C(1, 3) = 3, p ≥ N once again, move and reduce p getting p = 1 and .ooo.
.
Calculate N = C(1,4) = 4, p < N. Good, we've found final position for the first delimiter so leave it there and take second delimiter as current.
Calculate N = C(0,0) = 1, p ≥ N, p = 1 - 1 = 0, move, .oo.o
.
Calculate N = C(0,1) = 1, p < N, found final position for the second delimiter. Resulting arrangement is .oo.o
=> bbc
.
EDIT #1. Changed the algo description and added example.