Я пытаюсь создать всю возможную 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, но это дает мне повторение (я ищу комбинации, а не перестановки..... так что в примере выше, после набора (желтый, синий), (синий, желтый) не следует включать).
Выполните следующие действия:
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
снова, так как больше нет перестановок.
Готово.
bitset
как в примере ниже), чтобы смоделировать алгоритм.
Вы можете использовать следующее:
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()));
}
Мое решение, которое быстрее, чем использование 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);
И код быстрый.