Все комбинации из k элементов из n
Может ли кто-нибудь предоставить мне ссылку или псевдокод функции для нахождения всех комбинаций k элементов из n? возможно в STL. Мне не нужно вычислять n, выберите k, мне нужно перечислить все векторы чисел размера k.
Спасибо
5 ответов
В C++ дана следующая процедура:
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
/* Credits: Thomas Draper */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
Затем вы можете перейти к следующему:
// 9-choose-3
std::string s = "123456789";
std::size_t k = 3;
do
{
std::cout << std::string(s.begin(),s.begin() + k) << std::endl;
}
while(next_combination(s.begin(),s.begin() + k,s.end()));
Или для std::vector из int:
// 5-choose-3
std::size_t n = 5;
std::size_t k = 3;
std::vector<int> ints;
for (int i = 0; i < n; ints.push_back(i++));
do
{
for (int i = 0; i < k; ++i)
{
std::cout << ints[i];
}
std::cout << "\n";
}
while(next_combination(ints.begin(),ints.begin() + k,ints.end()));
http://howardhinnant.github.io/combinations.html
Ищите "for_each_combination". Если вы найдете что-то быстрее, пожалуйста, дайте мне знать. В отличие от других алгоритмов, которые я часто вижу, этот не требует, чтобы тип элемента был LessThanComparable.
Создайте вспомогательный вектор с n - k нулями, за которыми следуют k единиц. Ноль означает, что элемент в исходном контейнере не включен, тогда как один означает, что элемент включен.
Теперь используйте std::next_permutation для вспомогательного вектора, чтобы получить следующую комбинацию.
Вот ленивый пример псевдокода, который может сделать работу...
void nChooseK(array[n],k){
recurse("",array[n],k);
}
void recurse(initialString,array[n],k){
if(k == 0){
print initialString;
return;
}
for(i=0;i<n;i++){
tmpArray = array[0...i-1]+array[i+1...];//the array without the object to remove
recurse(initialString + array[i], tmpArray,k-1)
}
}
Вы можете использовать std::next_permutation, но это n! а не п выбрать к. Вы можете отфильтровать их после того, как вы их создали. Но это решение O(n!), Не совсем идеальное. Вот решение проб и ошибок:
int factorial(int value)
{
int result = 1;
for(int i = 1; i <= value; i++)
{
result *= i;
}
return result;
}
std::set<std::set<int>> binomial_coefficient(std::vector<int> input, int k)
{
std::set<std::set<int>> solutions;
for(unsigned int i = 0; i < factorial(input.size()); i++)
{
std::next_permutation(input.begin(), input.end());
solutions.insert(std::set<int>(input.begin(), input.begin() + k));
}
return solutions;
}