все комбинации из k элементов из n - PullRequest
22 голосов
/ 23 февраля 2011

Может ли кто-нибудь предоставить мне ссылку или псевдокод функции для нахождения всех комбинаций k элементов из n?возможно в STL.Мне не нужно вычислять n, выберите k, мне нужно перечислить все векторы чисел размера k.

Спасибо

Ответы [ 5 ]

25 голосов
/ 24 февраля 2011

В 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 of 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()));
10 голосов
/ 24 февраля 2011

http://howardhinnant.github.io/combinations.html

Поиск "for_each_combination". Если вы найдете что-то быстрее, пожалуйста, дайте мне знать. В отличие от других алгоритмов, которые я часто вижу, этот тип не требует, чтобы тип элемента был LessThanComparable.

3 голосов
/ 24 февраля 2011

Создайте вспомогательный вектор с n - k нулей, за которыми следуют k единиц. Ноль означает, что элемент в исходном контейнере не включен, тогда как один означает, что элемент включен.

Теперь используйте std :: next_permutation для вспомогательного вектора, чтобы получить следующую комбинацию.

1 голос
/ 23 февраля 2011

Вот ленивый пример псевдокода, который может выполнить работу ...

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)
    }        
}
0 голосов
/ 23 февраля 2011

Вы можете использовать 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...