std :: next_permutation (и std :: prev_permutation) переставляют все значения в диапазоне [first, last)
, заданные для общего числа n! перестановки (при условии, что все элементы уникальны).
возможно ли написать такую функцию:
template<class Iter>
bool next_permutation(Iter first, Iter last, Iter choice_last);
Это переставляет элементы в диапазоне [first, last)
, но выбирает только элементы в диапазоне [first, choice_last)
. то есть у нас может быть 20 элементов, и мы хотим перебрать все перестановки из 10 вариантов из них, 20 вариантов P 10 против 20 P 20.
- Iter - это итератор произвольного доступа для моих целей, но если он может быть реализован как двунаправленный итератор, то отлично!
- Чем меньше объем внешней памяти, тем лучше, но для моих целей это не имеет значения.
- Выбранные элементы на каждой итерации вводятся в первые элементы последовательности.
Можно ли реализовать такую функцию? Кто-нибудь знает какие-либо существующие реализации?
Вот по сути то, что я делаю, чтобы взломать это. Предложения о том, как это улучшить, также приветствуются.
- Начните с вектора
V
из N
элементов, из которых я хочу посетить каждую перестановку из R
элементов, выбранных из нее (R <= N
).
- Построить вектор
I
длины R
со значениями { 0, 1, 2, ... R - 1 }
, который будет служить индексом для элементов V
- На каждой итерации строится вектор
C
длины R
со значениями { V[I[0]], V[I[1]], ... V[I[R - 1]] }
- Сделайте что-нибудь со значениями в
C
.
- Примените функцию для перестановки элементов
I
и повторите итерацию, если это было возможно.
Эта функция выглядит так:
bool NextPermutationIndices(std::vector<int> &I, int N)
{
const int R = I.size();
for (int i = R - 1; ; --i) {
if (I[i] < N - R + i) {
++I[i];
return true;
}
if (i == 0)
return false;
if (I[i] > I[i-1] + 1) {
++I[i-1];
for (int j = i; j < R; ++j)
I[j] = I[j-1] + 1;
return true;
}
}
}
Эта функция очень сложна из-за всех возможных ошибок, связанных с ошибкой, а также все, что ее использует, сложнее, чем, вероятно, необходимо.
EDIT:
Оказывается, это было значительно проще, чем я мог себе представить. Начиная с здесь я смог найти точные реализации многих точных алгоритмов, которые мне нужны (комбинации, перестановки и т. Д.).
template<class BidirectionalIterator>
bool next_partial_permutation(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last)
{
std::reverse(middle, last);
return std::next_permutation(first, last);
}
Плюс там есть комбинированный алгоритм, который работает аналогичным образом. Однако реализация этого гораздо сложнее.