std::next_permutation (and std::prev_permutation) permute all values in the range [first, last)
given for a total of n! permutations (assuming that all elements are unique).
is it possible to write a function like this:
template<class Iter>
bool next_permutation(Iter first, Iter last, Iter choice_last);
That permutes the elements in the range [first, last)
but only chooses elements in the range [first, choice_last)
. ie we have maybe 20 elements and want to iterate through all permutations of 10 choices of them, 20 P 10 options vs 20 P 20.
- Iter is a random access iterator for my purposes, but if it can be implemented as a bidirectional iterator, then great!
- The less amount of external memory needed the better, but for my purposes it doesn't matter.
- The chosen elements on each iteration are input to the first elements of the sequence.
Is such a function possible to implement? Does anyone know of any existing implementations?
Here is essentially what I am doing to hack around this. Suggestions on how to improve this are also welcome.
- Start with a vector
V
ofN
elements of which I want to visit each permutation ofR
elements chosen from it (R <= N
). - Build a vector
I
of lengthR
with values{ 0, 1, 2, ... R - 1 }
to serve as an index to the elements ofV
- On each iteration, build a vector
C
of lengthR
with values{ V[I[0]], V[I[1]], ... V[I[R - 1]] }
- Do something with the values in
C
. - Apply a function to permute the elements of
I
and iterate again if it was able to.
That function looks like this:
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;
}
}
}
That function is very complicated due to all the possible off-by-one errors, as well everything using it are more complicated than is probably necessary.
EDIT:
It turns out that it was significantly easier than I had even imagined. From here, I was able to find exact implementations of many of the exact algorithms I needed (combinations, permutations, etc.).
template<class BidirectionalIterator>
bool next_partial_permutation(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last)
{
std::reverse(middle, last);
return std::next_permutation(first, last);
}
Plus there is a combination algorithm there that works in a similar way. The implementation of that is much more complication though.