I want to rank and unrank combinations with an Element distance constraint. Selected elements cannot repeated.
For example:
n := 10
elements choose from
k := 5
elements being choosen
d := 3
max distance between 2 choosen elements
1,3,5,8,9
matches the constraint
1,5,6,7,8
dont matches the constraint
How can ranking the combination with given distance constraint, where 1,2,3,4,5
is smaller than 1,2,3,4,6
? Is there a way do the ranking without compute the combinations with smaller Rank?
You can do this by first creating and populating a two-dimensional array, which I will call NVT for "number of valid tails", to record the number of valid "tails" that start at a certain position with a given value. For example, NVT[4][6] = 3, because a combination that has 6 in position #4 can end in 3 distinct ways: (…, 6, 7), (…, 6, 8), and (…, 6, 9).
Once you've done that, you can compute the rank of a combination C as follows:
0 +
(NVT[2][1] + NVT[2][2]) +
(NVT[3][1] + NVT[3][2] + NVT[3][3] + NVT[3][4]) +
(NVT[4][1] + NVT[4][2] + NVT[4][3] + NVT[4][4] + NVT[4][5] + NVT[4][6] + NVT[4][7]) + (NVT[5][1] + NVT[5][2] + NVT[5][3] + NVT[5][4] + NVT[5][5] + NVT[5][6] + NVT[5][7] + NVT[5][8]).
Conversely, you can find the combination C with a given rank r as follows:
Complexity analysis:
Implementation note: The details of the above are a bit fiddly; it would be easy to get an off-by-one error, or mix up two variables, or whatnot, if you don't have concrete data to look at. Since there are only 168 valid combinations for your example, I recommend generating all of them, so that you can reference them during debugging.
Possible additional optimization: If you expect n to be quite large, and you expect to do a lot of queries to "rank" and "unrank" combinations, then you might find it useful to create a second array, which I will call NVTLT for "number of valid tails less than", to record the number of valid "tails" that start at a certain position with a value less than a given value. For example, NVTLT[3][5] = NVT[3][1] + NVT[3][2] + NVT[3][3] + NVT[3][4], or if you prefer, NVTLT[3][5] = NVTLT[3][4] + NVT[3][4]. (You can do this as an in-place transformation, completely overwriting NVT, so it's an O(nk) pass with no additional space.) Using NVTLT instead of NVT for your queries will let you do binary search for values, rather than linear search, giving worst-case O(k log n) time instead of O(nk) time. Note that this optimization is even trickier than the above, so even if you intend to perform this optimization, I recommend starting with the above, getting it working perfectly, and only then adding this optimization.