Нахождение r-комбинаций вектора строк

0

Я пытаюсь создать всю возможную r-комбинацию данного списка строк. Например:

vector<string> original(n);
original[0] = "Brown";
original[1] = "Yellow";
original[2] = "Blue";

В этом случае n = 3 (3 цвета), и, например, если пользователь вводит r = 2, программа должна печатать:

    >Brown, Yellow
    >Brown, Blue
    >Yellow, Blue

Все, с кем я говорил, говорят, что используют маршрут next_permutation, но это дает мне повторение (я ищу комбинации, а не перестановки..... так что в примере выше, после набора (желтый, синий), (синий, желтый) не следует включать).

  • 0
    Может ли вход содержать повторения?
  • 0
    Если вы знаете алгоритм вывода комбинаций на основе последовательности битов, вы все равно можете использовать next_permutation () в битовой комбинации. Каждый бит, который включен, указывает элемент в комбинации.
Показать ещё 4 комментария
Теги:
algorithm
combinations

3 ответа

0
Лучший ответ

Выполните следующие действия:

1) Создайте серию из 3 бит.

2) Поскольку r равно 2, инициализируйте два самых правых бита до 1.

3) Выведите элементы в векторе, которые соответствуют битам, которые включены, например, если bitarray[0] равно 1, а затем выводит original[0], если bitarray[1] равен 1, а затем выводит original[1], и т.п.

4) Вызовите next_permutation() на битах, чтобы получить "следующий" бит.

Повторите шаги 3 и 4, пока next_permutation() не будет false.

Таким образом, в основном вам нужен бит массива из n элементов для начала и инициализации самых правых r бит до 1. Затем вы используете next_permutation для изменения битовой диаграммы. Я рекомендую вам сначала сделать это на бумаге, чтобы посмотреть, как все это работает.

Ниже приведен пример. Он жестко закодирован для 3 предметов, поэтому возьмите его за то, что он стоит.

#include <vector>
#include <algorithm>
#include <string>
#include <iostream>

void OutputVector (const std::vector<std::string>& theVect, bool* bArray, int nItems)
{
    for (int i = 0; i < nItems; ++i)
       if (bArray[i] == true)
         std::cout << theVect[i] << " ";
    std::cout << "\n";
}

using namespace std;

int main()
{
    std::vector<std::string> original = { "Brown", "Yellow", "Blue" };
    bool myBits[3] = { false };  // everything is false now
    myBits[1] = myBits[2] = true;  // set rightmost bits to true
    do  // start combination generator
    {
       OutputVector(original, myBits, 3);
    } while (next_permutation(myBits, myBits + 3));  // change the bit pattern
}

Принимая ваш пример:

Мы начинаем с этого битового шаблона (вызываем массив бит bitArray): 011

Это означает, что мы bitArray[1] original[1] и original[2] потому что bitArray[1] и bitArray[2] являются "истинными" (установлены в 1).

Когда next_permutation вызывается на эти биты, битовая диаграмма изменяется на это: 101

Мы bitArray[0] original[0] и original[2] потому что bitArray[0] и bitArray[2] являются "истинными".

next_permutation вызывается, изменения битового массива: 110

original[0] и original[1].

next_permutation вернет false, если next_permutation снова, так как больше нет перестановок.

Готово.

  • 0
    Пройдите алгоритм, который я описал выше, сначала карандашом и бумагой, чтобы понять его, а затем с реальным кодом. Чтобы сделать это простым, просто создайте массив bool из 3 элементов и установите для всех записей значение false, за исключением двух самых правых записей, которые будут статьями 1 и 2 (установите для них значение true). В основном вы используете массив bool в качестве руководства для вывода исходных значений массива.
  • 0
    @Not_NSA_I_Swear - Другой ответ показывает живой пример алгоритма, который я объяснил выше. Но если вы не понимаете аспект этого в C ++, это сейчас не важно - более важно понять, как это работает алгоритмически, поэтому вы должны увидеть это в действии, выполнив это «от руки» карандашом и бумагой. , Как только вы поймете логику происходящего, используйте любой C ++, который вы изучили (это не должно быть bitset как в примере ниже), чтобы смоделировать алгоритм.
Показать ещё 1 комментарий
2

Вы можете использовать следующее:

template <typename T>
void Combination(const std::vector<T>& v, std::size_t count)
{
    assert(count <= v.size());
    std::vector<bool> bitset(v.size() - count, 0);
    bitset.resize(v.size(), 1);

    do {
        for (std::size_t i = 0; i != v.size(); ++i) {
            if (bitset[i]) {
                std::cout << v[i] << " ";
            }
        }
        std::cout << std::endl;
    } while (std::next_permutation(bitset.begin(), bitset.end()));
}

Живой пример

  • 0
    Именно так, как я описал. +1.
0

Мое решение, которое быстрее, чем использование std::next_permutation:

#include "../combinations/combinations"
#include <iostream>
#include <string>
#include <vector>

int
main()
{
    std::vector<std::string> original(6);
    original[0] = "Brown";
    original[1] = "Yellow";
    original[2] = "Blue";
    original[3] = "Red";
    original[4] = "Green";
    original[5] = "Purple";
    for_each_combination(original.begin(), original.begin()+3, original.end(),
                         [](auto begin, auto end)
                         {
                              std::cout << "{";
                              bool print_comma = false;
                              for (; begin != end; ++begin)
                              {
                                   if (print_comma)
                                       std::cout << ", ";
                                   print_comma = true;
                                   std::cout << *begin;
                              }
                              std::cout << "}\n";
                              return false;
                         });
}

Найдите здесь for_each_combination.

Вывод:

{Brown, Yellow, Blue}
{Brown, Yellow, Red}
{Brown, Yellow, Green}
{Brown, Yellow, Purple}
{Brown, Blue, Red}
{Brown, Blue, Green}
{Brown, Blue, Purple}
{Brown, Red, Green}
{Brown, Red, Purple}
{Brown, Green, Purple}
{Yellow, Blue, Red}
{Yellow, Blue, Green}
{Yellow, Blue, Purple}
{Yellow, Red, Green}
{Yellow, Red, Purple}
{Yellow, Green, Purple}
{Blue, Red, Green}
{Blue, Red, Purple}
{Blue, Green, Purple}
{Red, Green, Purple}

Если ограничение на С++ 98 или если вы просто предпочитаете именованные функции, вы можете сделать:

#include "../combinations/combinations"
#include <iostream>
#include <string>
#include <vector>

bool
print(std::vector<std::string>::const_iterator begin,
      std::vector<std::string>::const_iterator end)
{
    std::cout << "{";
    bool print_comma = false;
    for (; begin != end; ++begin)
    {
        if (print_comma)
            std::cout << ", ";
        print_comma = true;
        std::cout << *begin;
    }
    std::cout << "}\n";
    return false;
}

int
main()
{
    std::vector<std::string> original(6);
    original[0] = "Brown";
    original[1] = "Yellow";
    original[2] = "Blue";
    original[3] = "Red";
    original[4] = "Green";
    original[5] = "Purple";
    for_each_combination(original.begin(), original.begin()+3, original.end(),
                         print);
}

Исходный код является открытым исходным кодом под лицензией программного обеспечения, но не является частью повышения. Не стесняйтесь использовать. Цель состоит в том, чтобы этот исходный код был свободен в использовании, и поощряется свободное использование. Если ваши адвокаты недовольны этой лицензией, дайте мне знать, и я постараюсь сделать их счастливыми, безвозмездно.

Эта же ссылка включает:

template <class BidirIter, class Function>
Function
for_each_permutation(BidirIter first,
                     BidirIter mid,
                     BidirIter last,
                     Function f);

template <class BidirIter, class Function>
Function
for_each_reversible_permutation(BidirIter first,
                                BidirIter mid,
                                BidirIter last,
                                Function f);

template <class BidirIter, class Function>
Function
for_each_circular_permutation(BidirIter first,
                              BidirIter mid,
                              BidirIter last,
                              Function f);

template <class BidirIter, class Function>
Function
for_each_reversible_circular_permutation(BidirIter first,
                                         BidirIter mid,
                                         BidirIter last,
                                         Function f);

template <class BidirIter, class Function>
Function
for_each_combination(BidirIter first,
                     BidirIter mid,
                     BidirIter last,
                     Function f);

И код быстрый.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню