#pragma once #include #include #include #include #include size_t choose(size_t n, size_t k) { if (k == 0) return 1; return n * choose(n - 1, k - 1) / k; } template class ComboIterator { private: const std::vector &options; std::vector bits; std::vector curr; int at; void set_curr() { for (int i = 0, j = 0; i < bits.size(); ++i) { if (bits[i]) curr[j++] = options[i]; } } public: ComboIterator(const std::vector &options, int k, int at = 0) : options(options), bits(options.size()), curr(k), at(at) { std::fill(bits.begin(), bits.begin() + k, true); set_curr(); } [[nodiscard]] bool operator==(const ComboIterator &o) const { return at == o.at; } [[nodiscard]] bool operator!=(const ComboIterator &o) const { return at != o.at; } auto operator*() const { return curr; } const auto &operator->() const { return &this; } auto operator++(int) { std::prev_permutation(bits.begin(), bits.end()); set_curr(); ++at; return *this; } auto operator++() &{ auto res = *this; (*this)++; return res; } auto operator--(int) { std::next_permutation(bits.begin(), bits.end()); set_curr(); --at; return *this; } auto operator--() &{ auto res = *this; (*this)--; return res; } }; template class Combos { private: const std::vector options; int k; int size; public: Combos(const std::vector &options, int k) : options(options), k(k), size(choose(options.size(), k)) { } ComboIterator begin() const { return ComboIterator(options, k); } ComboIterator end() const { return ComboIterator(options, k, size); } };