Перечисление powerset (то есть всех комбинаций всех размеров) может использовать адаптацию алгоритма двоичного приращения.
template< class I, class O > // I forward, O bidirectional iterator
O next_subset( I uni_first, I uni_last, // set universe in a range
O sub_first, O sub_last ) { // current subset in a range
std::pair< O, I > mis = std::mismatch( sub_first, sub_last, uni_first );
if ( mis.second == uni_last ) return sub_first; // finished cycle
O ret;
if ( mis.first == sub_first ) { // copy elements following mismatch
std::copy_backward( mis.first, sub_last, ++ (ret = sub_last) );
} else ret = std::copy( mis.first, sub_last, ++ O(sub_first) );
* sub_first = * mis.second; // add first element not yet in result
return ret; // return end of new subset. (Output range must accommodate.)
}
Требование двунаправленного итератора, к сожалению, может быть обойдено.
Я собирался заставить его обрабатывать идентичные элементы (мультимножества), но мне нужно идти спать: v (.
Использование:
#include <iostream>
#include <vector>
using namespace std;
char const *fruits_a[] = { "apples", "beans", "cherries", "durian" };
vector< string > fruits( fruits_a, fruits_a + sizeof fruits_a/sizeof *fruits_a );
int main() {
vector< string > sub_fruits( fruits.size() );
vector< string >::iterator last_fruit = sub_fruits.begin();
while (
( last_fruit = next_subset( fruits.begin(), fruits.end(),
sub_fruits.begin(), last_fruit ) )
!= sub_fruits.begin() ) {
cerr << "size " << last_fruit - sub_fruits.begin() << ": ";
for ( vector<string>::iterator fit = sub_fruits.begin(); fit != last_fruit; ++ fit ) {
cerr << * fit << " ";
}
cerr << endl;
}
}
РЕДАКТИРОВАТЬ: Вот версия для мультимножеств. Набор не должен быть отсортирован, но идентичные элементы должны быть сгруппированы вместе.
#include <iterator>
#include <algorithm>
#include <functional>
template< class I, class O > // I forward, O bidirectional iterator
I next_subset( I uni_first, I uni_last, // set universe in a range
O sub_first, O sub_last ) { // current subset in a range
std::pair< O, I > mis = std::mismatch( sub_first, sub_last, uni_first );
if ( mis.second == uni_last ) return sub_first; // finished cycle
typedef std::reverse_iterator<O> RO;
mis.first = std::find_if( RO(mis.first), RO(sub_first), std::bind1st(
std::not_equal_to< typename std::iterator_traits<O>::value_type >(),
* mis.second ) ).base(); // move mis.first before identical grouping
O ret;
if ( mis.first != sub_first ) { // copy elements after mismatch
ret = std::copy( mis.first, sub_last, ++ O(sub_first) );
} else std::copy_backward( mis.first, sub_last, ++ (ret = sub_last) );
* sub_first = * mis.second; // add first element not yet in result
return ret;
}
#include <vector>
#include <iostream>
using namespace std;
char const *fruits_a[] = { "apples", "apples", "beans", "beans", "cherries" };
vector< string > fruits( fruits_a, fruits_a + sizeof fruits_a/sizeof *fruits_a );
int main() {
vector< string > sub_fruits( fruits.size() );
vector< string >::iterator last_fruit = sub_fruits.begin();
while (
( last_fruit = next_subset( fruits.begin(), fruits.end(),
sub_fruits.begin(), last_fruit )
) != sub_fruits.begin() ) {
cerr << "size " << last_fruit - sub_fruits.begin() << ": ";
for ( vector<string>::iterator fit = sub_fruits.begin(); fit != last_fruit; ++ fit ) {
cerr << * fit << " ";
}
cerr << endl;
}
}
Выход:
size 1: apples
size 2: apples apples
size 1: beans
size 2: apples beans
size 3: apples apples beans
size 2: beans beans
size 3: apples beans beans
size 4: apples apples beans beans
size 1: cherries
size 2: apples cherries
size 3: apples apples cherries
size 2: beans cherries
size 3: apples beans cherries
size 4: apples apples beans cherries
size 3: beans beans cherries
size 4: apples beans beans cherries
size 5: apples apples beans beans cherries