Вот реализация в Mathematica из пакета Combinatorica .Семантика довольно общая, поэтому я думаю, что это полезно.Пожалуйста, оставьте комментарий, если вам нужно что-то объяснить.
UnrankKSubset::usage = "UnrankKSubset[m, k, l] gives the mth k-subset of set l, listed in lexicographic order."
UnrankKSubset[m_Integer, 1, s_List] := {s[[m + 1]]}
UnrankKSubset[0, k_Integer, s_List] := Take[s, k]
UnrankKSubset[m_Integer, k_Integer, s_List] :=
Block[{i = 1, n = Length[s], x1, u, $RecursionLimit = Infinity},
u = Binomial[n, k];
While[Binomial[i, k] < u - m, i++];
x1 = n - (i - 1);
Prepend[UnrankKSubset[m - u + Binomial[i, k], k-1, Drop[s, x1]], s[[x1]]]
]
Использование похоже на:
UnrankKSubset[1, 4, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}]
<b> {1, 2, 3, 5}</b>
Как вы можете видеть, эта функция работает на наборах.
Ниже приведена моя попытка объяснить приведенный выше код.
UnrankKSubset - это рекурсивная функция с тремя аргументами, которая называется (m, k, s):
m
Целое число, «ранг» комбинации в лексикографическом порядке, начиная с нуля. k
целое число, количество элементов в каждой комбинации s
Список,элементы, из которых можно собрать комбинации
В рекурсии есть два граничных условия:
для любого ранга m
и любого списка s
,если количество элементов в каждой комбинации k
равно 1
, то:
возвращает элемент m + 1
списка s
, сам по себе в списке.
(+ 1
необходимо, потому что Mathematica индексирует от одного, а не от нуля. Я считаю, что в C ++ это будет s [m])
, если ранг m
равен 0
, то для любого k
и любых s
:
возвращаются первые k
элементов s
Основная рекурсивная функция для любых других аргументов, кроме указанных выше:
локальные переменные: (i
, n
, x1
, u
)
Binomial
является биномиальным коэффициентом: Binomial[7, 5]
= 21
Do:
i = 1
n = Length[s]
u = Binomial[n, k]
While[Binomial[i, k] < u - m, i++];
x1 = n - (i - 1);
Затем возвращаем:
Prepend[
UnrankKSubset[m - u + Binomial[i, k], k - 1, Drop[s, x1]],
s[[x1]]
]
То есть «предваряем»x1
элемент списка s
(вспомните индексы Mathematica от одного, поэтому я считаю, что это будет индекс x1 - 1
в C ++) в список, возвращаемый рекурсивно вызываемой функцией UnrankKSubset с аргументами:
m - u + Binomial[i, k]
k - 1
Drop[s, x1]
Drop[s, x1]
- остаток списка s
с первым x1
элементы удалены.
Если что-либо из вышеперечисленного непонятно, или если вы хотели пояснить алгоритм, а не объяснение кода, пожалуйста, оставьте комментарий, и япопробую еще раз.