Как генерировать сочетания K
элементов из N
при условии что среди исходного множества некоторые элементы одинаковы? Например:
[1, 1, 2, 3, 3, 3] по 3 [1, 1, 2] [1, 1, 3] [1, 2, 3] [1, 3, 3] [2, 3, 3] [3, 3, 3]
Несколько неуклюжий алгоритм можно вывести из обычной генерации сочетаний без повторений, однако "неуклюжесть" смущает и интересно есть ли другой путь. К сожалению "сочетания с повторениями" по интернетам в основном дают ссылки на несколько другую трактовку задачи, если я правильно понял, с произвольным количеством повторений для каждого элемента.
В общем, буду рад ссылкам / намёкам.
Вру.
А в чём неуклюжесть? Просто во время того, как хотите поставить очередной элемент, ещё перебрать, сколько этих элементов сразу поставить подряд. Всё остальное так же.
Как и с обычными сочетаниями, достаточно реализовать фукнцию "следующее сочетание". Сочетание с ограничеными повторениями будем хранить как массив
x[]
, к котором записано, сколько раз каждое число встречается, причём сумма всех чисел равнаk
(так же как и в обычных сочетаниях, только в обычных сочетаниях любойx[i]
от0
до1
, а здесь — от0
до определённого числаd[i]
).Давайте найдём лексикографически следующее сочетание. Для этого надо найти ближайший к концу элемент, который можно увеличить на 1 (то есть, максимальное
i
такое, чтоx[i] < d[i]
, и хотя бы для какого-тоj>i
выполненоx[j] > 0
) и сделатьx[i]++
. Ну а потом надо хвост массива сделать лексикографически минимальным. Пустьm
— максимальное из встречающихся чисел, аsum
— сумма всехx[j]
дляj>i
(с учётом нового значенияx[i]
). Тогда делаем так:Естественно, множество надо для начала сжать. Тогда амортизированное время одного выполнения функции
next()
будетO(1)
.Ну да, эту вот функцию я и имел в виду "неуклюжей" :)
Но спасибо, конечно — действительно не так она и страшна, и альтернатив вроде не нашлось. :)
Why not to use bitmasks?
Easily you can generate all possible subsets and work only with the subsets containing exactly k elements.
If you don't want to generate unnecessary subsets, I provide you a nice code I found in topcoder forums:
next(x) returns the next integer > x with the same number of bits turned on in O(logN).
ur problem can be reduced to the following:
given a vector (a1, a2, ... an), find the number of vectors (b1, b2, ... bn) such that:
on hindsight this looks to be solvable using dynamic programming, but i'm not very sure.
Use backtracking, with an element, decide how many will it be appeared.
Call backtrack(1, 1). All arrays above are one-based.