// Combination algorithm implementation // // Copyright (C) 2004 - 2006, BenBear // // More information in http://www.bxmy.org // This file is an algorithm of the combination. This library is free // software; you can redistribute it and/or modify it under the terms // of the GNU General Public License as published by the Free Software // Foundation; either version 2, or (at your option) any later // version. // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // You should have received a copy of the GNU General Public License // along with this library; see the file COPYING. If not, write to // the Free Software Foundation, 59 Temple Place - Suite 330, Boston, // MA 02111-1307, USA. #ifndef __btb_combination_hpp_def #define __btb_combination_hpp_def #include namespace btb { //////////////////////////////////////////////////////////////////// // combination for STL permutation // // combination_init (first, middle, last) // combination_adjust (first, middle, last) // combination (first1, last1, first2, last2) // next_combination (first, middle, last) // prev_combination (first, middle, last) //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// // twice_merge: merge [first1, last1) and [first2, last2), then fill // the min element to [first1, last1), left to [first2, // last2) //////////////////////////////////////////////////////////////////// template void twice_merge (Iter first1, Iter last1, Iter first2, Iter last2) { typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::difference_type diff_t; if ((first1 == last1) || (first2 == last2)) return; first1 = std::upper_bound(first1, last1, *first2); if (first1 == last1) return; last2 = std::lower_bound(first2, last2, *(last1-1)); if (first2 == last2) return; diff_t len1 = std::distance(first1, last1); diff_t len2 = std::distance(first2, last2); bool min1 = len1 < len2; diff_t lent = min1 ? len1 : len2; value_type *tmp = new value_type[lent]; if (min1) { std::copy(first1, last1, tmp); Iter p = first2; Iter q = tmp; Iter i; for (i = first1; i != last1; ++i) if (*p < *q) *i = *p++; else *i = *q++; for (i = first2; (i != last2) && (p != last2); ++i) if (*p < *q) *i = *p++; else *i = *q++; for (; i != last2; ++i, ++q) *i = *q; } else { std::copy(first2, last2, tmp); Iter p = last1; Iter q = tmp+lent; Iter i; for (Iter i = last2; i != first2;) if (*(p-1) < *(q-1)) *--i = *--q; else *--i = *--p; for (i = last1; (i != first1) && (p != first1);) if (*(p-1) < *(q-1)) *--i = *--q; else *--i = *--p; for (; i != first1;) *--i = *--q; } delete[] tmp; } /////////////////////////////////////////////////////////////////// // __combination_sort: merge sort the [first, last) /////////////////////////////////////////////////////////////////// template void __combination_sort (Iter first, Iter last) { typedef typename std::iterator_traits::difference_type diff_t; diff_t len = std::distance(first, last); if (len <= 1) return; if (len == 2) { if (*first > *--last) std::iter_swap (first, last); } else { Iter middle = first; std::advance(middle, len / 2); __combination_sort (first, middle); __combination_sort (middle, last); twice_merge (first, middle, middle, last); } } ////////////////////////////////////////////////////////////////////// // combination_init: init the (first, midle, last) to the min or the // max combination ////////////////////////////////////////////////////////////////////// template void combination_init (Iter first, Iter middle, Iter last, bool min = true) { __combination_sort (first, middle); __combination_sort (middle, last); if (min) twice_merge (first, middle, middle, last); else twice_merge (middle, last, first, middle); } ////////////////////////////////////////////////////////////////////// // combination_adjust: make the (first, middle, last) to a right // combination. [first, middle) are the elements // selected in, [middle, last) are selected out ////////////////////////////////////////////////////////////////////// template void combination_adjust (Iter first, Iter middle, Iter last) { __combination_sort (first, middle); __combination_sort (middle, last); } ///////////////////////////////////////////////////////////////////// // combination: get next combination. // // [first1, last1): the elements selected in \\ // [first2, last2): the elements selected out ///////////////////////////////////////////////////////////////////// template bool combination (Iter first1, Iter last1, Iter first2, Iter last2) { if ((first1 == last1) || (first2 == last2)) return false; Iter qmax = last2; --qmax; Iter pout1 = std::lower_bound(first1, last1, *qmax); bool fin = pout1 == first1; Iter left1, left2; if (!fin) { Iter pout = pout1; --pout; Iter qin = std::upper_bound(first2, last2, *pout); std::iter_swap (pout, qin); left1 = pout; ++left1; left2 = qin; ++left2; } else { left1 = first1; left2 = first2; } twice_merge (left1, last1, left2, last2); return !fin; } ///////////////////////////////////////////////////////////////////// // next_combination: get next combination. // // [first, middle): the elements selected in \\ // [middle, last): the elements selected out ///////////////////////////////////////////////////////////////////// template inline bool next_combination (Iter first, Iter middle, Iter last) { return combination (first, middle, middle, last); } ///////////////////////////////////////////////////////////////////// // prev_combination: get prev combination. // // [first, middle): the elements selected in \\ // [middle, last): the elements selected out ///////////////////////////////////////////////////////////////////// template inline bool prev_combination (Iter first, Iter middle, Iter last) { return combination (first, middle, middle, last); } } #endif #include using namespace std; using namespace btb; int main() { int a[7] = {1, 2, 3, 4, 5, 6, 7}; int c = 0; int len = 5; do { cout << "--[\t"; for (int i = 0; i < c; ++i) cout << a[i] << '\t'; cout << " <>\t"; for (int i = c; i < len; ++i) cout << a[i] << '\t'; cout << "]" << endl; //cin.get(); } while (next_combination(a, a+c, a+len) || (++c <= len)); cin.get(); c = 0; len = 5; a[1] = 1; a[4] = 4; do { cout << "--[\t"; for (int i = 0; i < c; ++i) cout << a[i] << '\t'; cout << " <>\t"; for (int i = c; i < len; ++i) cout << a[i] << '\t'; cout << "]" << endl; //cin.get(); } while (next_combination(a, a+c, a+len) || (++c <= len)); cin.get(); }