let us suppose have following pairs
0 -1
0 -2
0 -3
1- 2
2 -3
3- 4
2 -4
4- 5
5 -6
i would like to insert those pairs into vector , so that i should have each element only one times , for instance
start with empty vector :
0-1 is inserted
now we are checking 0-2 , there exist 0, but not 2, so 0-2 is inserted, we have
0-1
0-2
now 0-3 , 3 is not in the list, so we can insert
0-1
0-2
0-3
now lets us consider 1-2 , of course we have both of them , so skip, now let us consider 2-3, again we can skip, 3-4 , 3 exist but not 4, so we can insert
3-4 , after inserting of 4 , 4 also exist,so reject 2-4 then comes 4-5 and 5-6, so we have following list
0-1
0-2
0-3
3-4
4-5
5-6
i have following code
#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
struct edge
{
int a, c;
float weight;//edge a-c has weight
bool operator() (edge x, edge y)
{
x.weight < y.weight;
}
};
int noncyclical_sum(vector<edge>s)
{
int total = 0;
std::vector<std::pair<int, int>> b;
auto m = make_pair(s[0].a, s[0].c);
b.push_back(m);
total = total + s[0].weight;
vector<edge>::iterator it;
for (int i = 1; i < s.size(); i++)
{
auto m = make_pair(s[i].a, s[i].c);
//if (find(b.begin(), b.end(), s[i].a) != b.end() && find(b.begin(), b.end(), s[i].c) != b.end())
if (find(b.begin(), b.end(), m.first) != b.end() && find(b.begin(), b.end(), m.second) != b.end())
{
continue; //both element is in the vector
}
else
{
b.push_back(m);
total = total + s[i].weight;
}
std::vector<std::pair<int, int>>::iterator ii;
for (ii = b.begin(); ii != b.end(); ii++)
cout << ii->first << " " << ii->second;
}
}
int main()
{
return 0;
}
at first time , i have pushed first pair, starting from the second one, i am checking if at the same time both element is in vector, i am rejecting pairs and continue, otherwise i push new pairs and continuing , but i have following error
Severity Code Description Project File Line Suppression State
Error C2678 binary '==': no operator found which takes a left-hand operand of type 'std::pair<int,int>' (or there is no acceptable conversion) kurskal_algorithm c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.10.25017\include\xutility 3161
what is wrong ? thanks in advance
The problem is in this line:
if (find(b.begin(), b.end(), m.first) != b.end() && find(b.begin(), b.end(), m.second) != b.end())
Let's check the arguments of std::find call: b.begin() and b.end() are std::vector<std::pair<int, int>>::iterators while m.first is int.
So, you're trying to find int in the vector of pairs. You can't do that.
Also, all of your functions lack the required return statements.
Related
I have this problem: Given a vector with n numbers, sort the numbers so that the even ones will be on odd positions and the odd numbers will be on even positions. E.g. If I have the vector 2 6 7 8 9 3 5 1, the output should be 2 7 6 9 8 3 5 1 . The count should start from 1. So on position 1 which is actually index 0 should be an even number, on position 2 which is actually index 1 should be an odd number and so on. Now this is easy if the odd and even numbers are the same, let's say 4 even number and 4 odd numbers in the vector, but what if the number of odd numbers differs from the number of even numbers like in the above example? How do I solve that. I attached the code with one of the tries I did, but it doesn't work. Can I get some help please. I ask you to keep it simple that means only with vectors and such. No weird methods or anything cause I'm a beginner and I only know the basics. Thanks in advance!
I have to mention that n initial is globally declared and is the number of vector elements and v_initial is the initial vector with the elements that need to be rearranged.
The task says to add the remaining numbers to the end of the vector. Like if there are 3 odd and 5 even numbers, The 2 extra even numbers should be thrown at the end of the vector
void vector_pozitii_pare_impare(int v_initial[])
{
int v_pozitie[50],c1=0,c2=1;
for (i = 0; i < n_initial; i++)
{
if (v_initial[i] % 2 == 0)
{
bool isTrue = 1;
for (int k = i + 1; k < n_initial; k++)
{
if (v_initial[k] % 2 != 0)
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c1] = v_initial[i];
c1++;
}
else
{
v_pozitie[c1] = v_initial[i];
c1 += 2;
}
}
else
{
bool isTrue = 1;
for (int j = i + 1; j < n_initial; j++)
{
if (v_initial[j] % 2 == 0)
{
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c2] = v_initial[i];
c2++;
}
else
{
v_pozitie[c2] = v_initial[i];
c2 += 2;
}
}
}
}
This may not be a perfect solution and it just popped out right off my mind without being tested or verified, but it's just to give you an idea.
(Let A,B,C,D be odd numbers and 0,1,2 even numbers correspondingly)
Given:
A 0 B C D 1 2 (random ordered list of odd/even numbers)
Wanted:
A 0 B 1 C 2 D (input sequence altered to match the wanted odd/even criteria)
Next, we invent the steps required to get from given to wanted:
// look at 'A' -> match, next
// Result: A 0 B C D 1 2
// look at '0' -> match, next
// Result: A 0 B C D 1 2
// look at 'B' -> match, next
// Result: A 0 B C D 1 2
// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2
// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2
// continue until the whole list has been consumed.
As I said, this algorithm may not be perfect, but my intention is to give you an example on how to solve these kinds of problems. It's not good to always think in code first, especially not with a problem like this. So you should first think about where you start, what you want to achieve and then carefully think of how to get there step by step.
I feel I have to mention that I did not provide an example in real code, because once you got the idea, the execution should be pretty much straight forward.
Oh, and just a small remark: Almost nothing about your code is C++.
A simple solution, that is not very efficient would be to split the vector into 2 vectors, that contain even and uneven numbers and then always take one from the even, one from the uneven and then the remainder, from the one that is not completely entered.
some c++ (that actually uses vectors, but you can use an array the same way, but need to change the pointer arithmetic)
I did not test it, but the principle should be clear; it is not very efficient though
EDIT: The answer below by #AAAAAAAAARGH outlines a better algorithmic idea, that is inplace and more efficient.
void change_vector_even_uneven(std::vector<unsigned>& in_vec){
std::vector<unsigned> even;
std::vector<unsigned> uneven;
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if ((*it) % 2 == 0)) even.push_back(*it);
else uneven.push_back(*it);
}
auto even_it = even.begin();
auto uneven_it = uneven.begin();
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if (even_it == even.end()){
(*it) = (*uneven_it);
uneven_it++;
continue;
}
if (uneven_it == uneven.end()){
(*it) = (*even_it);
even_it++;
continue;
}
if ((it - in_vec.begin()) % 2 == 0){
(*it) = (*even_it);
even_it++;
}
else{
(*it) = (*uneven_it);
uneven_it++;
}
}
}
The solutions is simple. We sort the even and odd values into a data structure. In a loop, we iterate over all source values. If they are even (val & 2 == 0) we add them at the end of a std::deque for evens and if odd, we add them to a std::deque for odds.
Later, we we will extract the the values from the front of the std::deque.
So, we have a first in first out principle.
The std::deque is optimized for such purposes.
Later, we make a loop with an alternating branch in it. We, alternatively extract data from the even queue and then from the odd queue. If a queue is empty, we do not extract data.
We do not need an additional std::vector and can reuse the old one.
With that, we do not need to take care for the same number of evens and odds. It will of course always work.
Please see below one of millions of possible solutions:
#include <iostream>
#include <vector>
#include <deque>
int main() {
std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
// Show initial data
std::cout << "\nInitial data: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
// We will use a deques to store odd and even numbers
// With that we can efficiently push back and pop front
std::deque<int> evenNumbers{};
std::deque<int> oddNumbers{};
// Sort the original data into the specific container
for (const int number : testData)
if (number % 2 == 0)
evenNumbers.push_back(number);
else
oddNumbers.push_back(number);
// Take alternating the data from the even and the odd values
bool takeEven{ true };
for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
if (takeEven) { // Take even numbers
if (not evenNumbers.empty()) { // As long as there are even values
testData[i] = evenNumbers.front(); // Get the value from the front
evenNumbers.pop_front(); // Remove first value
++i;
}
}
else { // Now we take odd numbers
if (not oddNumbers.empty()) { // As long as there are odd values
testData[i] = oddNumbers.front(); // Get the value from the front
oddNumbers.pop_front(); // Remove first value
++i;
}
}
// Next take the other container
takeEven = not takeEven;
}
// Show result
std::cout << "\nResult: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
return 0;
}
Here is yet another solution (using STL), in case you want a stable result (that is, the order of your values is preserved).
#include <algorithm>
#include <vector>
auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
// split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
const auto it = std::stable_partition(
ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
auto results = std::vector<int>{};
results.reserve(ints.size());
// merge both parts with equal size
auto a = ints.begin(), b = it;
while (a != it && b != ints.end()) {
results.push_back(*a++);
results.push_back(*b++);
}
// copy remaining values to end of list
std::copy(a, it, std::back_inserter(results));
std::copy(b, ints.end(), std::back_inserter(results));
The result ist [2, 7, 6, 9, 8, 3, 5, 1]. The complexity is O(n).
This answer, like some of the others, divides the data and then reassembles the result. The standard library std::partition_copy is used to separate the even and odd numbers into two containers. Then the interleave function assembles the result by alternately copying from two input ranges.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
{
for (;;) {
if (first1 == last1) {
return std::copy(first2, last2, dest);
}
*dest++ = *first1++;
if (first2 == last2) {
return std::copy(first1, last1, dest);
}
*dest++ = *first2++;
}
}
void reorder_even_odd(std::vector<int> &data)
{
auto is_even = [](int value) { return (value & 1) == 0; };
// split
std::vector<int> even, odd;
std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
// merge
interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
}
int main()
{
std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
reorder_even_odd(data);
for (int value : data) {
std::cout << value << ' ';
}
std::cout << '\n';
}
Demo on Compiler Explorer
As suggested, I am using vectors and STL.
No need to be a great mathematician to understand v_pozitie will start with pairs of odd and even and terminate with the integers not in the initial pairs.
I am then updating three iterators in v_positie (no need of temporary containers to calculate the result) : even, odd and end,(avoiding push_back) and would code this way :
#include <vector>
#include <algorithm>
void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
int nodd (0), neven (0);
std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
nodd += n%2;
});
neven = v_initial.size () - nodd;
int npair (neven < nodd ?neven:nodd);
npair *=2;
std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
if (npair) {
switch (s%2) {
case 0 :
*ieven++ = s;
++ieven;
break;
case 1 :
*iodd++ = s;
++iodd;
break;
}
--npair;
}
else *iend++ = s;
});
}
int main (int argc, char* argv []) {
const int N = 8;
int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
std::vector<int> v_initial (tab, (int*)&tab [N]);
std::cout << "\tv_initial == ";
std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
std::vector<int> v_pozitie (v_initial.size (), -1);
vector_pozitii_pare_impare (v_initial, v_pozitie);
std::cout << "\tv_pozitie == ";
std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
}
I have a code for "Minimum number of jumps to reach end of the array with its sequence using recursion". But I am not able to print the sequence. ( There is nothing in vector vec to print )
Any help will be appreciated.
Explanation :
I want to reach from 1st element ( i.e. 2) to
last element ( i.e. 4) of the array in minimum Jump.
How Jump will be :
1st element is 2. It means I can make upto 2 jumps in array. If I take 1st jump then I can reach 2nd element ( i.e. 3) or if I take
2nd jump then I can reach 3rd element (i.e. 1)
2nd element is 3 ,so I can make maximum 3 jumps. In 1st jump I can reach to 1 , in 2nd jump I can reach to 0 and in 3rd jump I can
reach to 4
In this way I want to reach from 1st element to last element of the array in minimum number of jumps.
So output will be like , from 1st element 2, I will jump to 3. Then from 3 I will jump to 4 (last element). So 2 Jumps. ( 2 - 3 - 4 )
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int jump(int arr[], int n, int start, vector<int> &vec)
{
if(start == n-1) // if start is the last element in array
return 0;
if( arr[start] == 0) // if array element is 0
return 0;
vector<int> vec1 = vec;
vector<int> vec2 = vec;
int minimum = INT_MAX;
for( int i = 1 ; i <= arr[start]; i++ )
{
vec1.push_back(start);
int _jump = 1 + jump( arr, n, start+i, vec1); // considering every jump
vec = (_jump < minimum) ? vec1 : vec2;
minimum = min(minimum, _jump);
}
return minimum;
}
int main()
{
int arr[] = { 2, 3, 1, 0, 4 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vec;
cout << "Number of jumps " << jump(arr, n, 0, vec) << endl;
cout<<"Sequence is "<<endl;
for( auto x : vec)
cout << x <<" ";
return 0;
}
output
Number of jumps 2
Sequence is
Expected output
Number of jumps 2
Sequence is 2 3 4
Here is an example that will set a vector where each index stores the correct next step in the sequence after visiting that index. I leave it to you to code following the sequence from the first element to the end, using the result vector. I also corrected this condition if( arr[start] == 0) to return "infinity" since if we visit this element, we cannot complete the sequence.
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int jump(int arr[], int n, int start, vector<int> &vec)
{
if(start == n-1) // if start is the last element in array
return 0;
if( arr[start] == 0) // if array element is 0
return INT_MAX - n;
int minimum = INT_MAX;
int step;
for( int i = 1 ; i <= arr[start]; i++ )
{
int _jump = 1 + jump( arr, n, start+i, vec); // considering every jump
if (_jump < minimum){
minimum = _jump;
step = start + i;
}
}
vec.at(start) = step;
return minimum;
}
int main()
{
int arr[] = { 2, 3, 1, 0, 4 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vec(n, -1);
cout << "Number of jumps " << jump(arr, n, 0, vec) << endl;
cout<<"Vector: "<<endl;
for( auto x : vec)
cout << x <<" ";
return 0;
}
Essentially, this is the minimal fix so that the sample data would works. I have not check all edge cases. For example, one might want to print something else than the value of INT_MAX is the end is not reachable.
Problem 1
You want to output values (i.e. 2, 3, 4 in your example) and not index (0, 1, 4). Thus you must push values instead of indexes.
vec1.push_back(arr[start]);
Problem 2
if(start == n-1) // if start is the last element in array
return 0;
This will not add the final value when the end is reached. You must add last value with:
vec.push_back(arr[start]);
Problem 3
if( arr[start] == 0) // if array element is 0
return 0;
A sequence that does not reach the end, would be considered to be very good. You should return a large value. Since _jump is 1 + return value of jump, the return value should be INT_MAX - 1 and minimum should also be initialized to that value for same reason.
Alternatively, you could return other values like n too instead.
Problem 4
Finally, the following condition is incorrect:
vec = (_jump < minimum) ? vec1 : vec2;
When the condition is not verified, it is vect2 that need to be copied in vec1 since the loop uses vect1.
Given n points in a two-dimensional space, sort all the points in ascending order.
(x1,y1) > (x2,y2) if and only if (x1>x2) or (x1==x2 && y1<y2)
Input specification:
The first line consists of an integer t, the number of test cases. Then for each test case, the first line consists of an integer n, the number of points. Then the next n lines contain two integers xi, yi which represents the point.
Output Specification:
For each test case print the sorted order of the points.
Input constraints:
1 <= t <= 10
1 <= n <= 100000
- 10 ^ 9 <= co - ordinates <= 10 ^ 9
NOTE: Strict time limit. Prefer scanf/printf/BufferedReader instead of cin/cout/Scanner.
Sample Input:
1
5
3 4
-1 2
5 -3
3 3
-1 -2
Sample Output:
-1 2
-1 -2
3 4
3 3
5 -3
I declared a set, now I want to sort descendingly(values) if the keys are equal. Here is my code:
int main()
{
int n, i, hold = 0;
set<pair<int, int>>s;
int x, y, t;
set<pair<int, int>>::iterator it;
SF(t)
while (t--)
{
SF(n) while (n--) {
SF(x) SF(y)
s.insert({ x,y });
}
for (it = s.begin(); it != s.end(); it++) {
PF(it->first) printf(" "); PF(it->second); printf("\n");
}
s.clear();
}
return 0;
}
my output
-1 -2
-1 2
3 3
3 4
5 -3
I want the key values to be sorted descendingly if the keys are same.
The std::set uses by default std::less as default comparator for comparing the elements inserting to it.
In your case, you have std::pair<int,int> as your element type hence, the std::set uses the default operator< of std::pair defined in the standard and hence you are not getting the result you want.
In order to achieve your custom style comparison, you need to provide a custom comparator
template<
class Key,
class Compare = std::less<Key>,
// ^^^^^^^^^^^^^^^ --> instead of this
class Allocator = std::allocator<Key>
> class set;
which should meet the requirements of compare.
Since C++11 you could also use a lambda function for this:
Following is a sample example code: (See Online)
#include <iostream>
#include <set>
using pairs = std::pair<int, int>;
int main()
{
// custom compare
const auto compare = [](const pairs &lhs, const pairs &rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
};
std::set<pairs, decltype(compare)> mySet(compare);
mySet.emplace(3, 4);
mySet.emplace(-1, 2);
mySet.emplace(5, -3);
mySet.emplace(3, 3);
mySet.emplace(-1, -2);
for (const auto& it : mySet)
std::cout << it.first << " " << it.second << std::endl;
}
Output:
-1 2
-1 -2
3 4
3 3
5 -3
Set doesn't sort the way you want by default, so you have to supply your own comparison function.
struct MyComp
{
bool operator()(const pair<int,int>& x, const pair<int,int>& y) const
{
return x.first < y.first || (x.first == y.first && x.second > y.second);
}
};
set<pair<int,int>, MyComp> s;
As Jejo and others have answered, you can create a custom comparitor to specify how you want your points sorted:
// custom compare
const auto compare = [](const pairs &lhs, const pairs &rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
};
set<pair<int, int>, decltype(compare)> mySet(compare);
However, if performance is your concern, you will probably find that using a std::vector and calling std::sort is much faster than the std::set/insert alternative:
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n, i, hold = 0;
vector<pair<int, int>> v;
int x, y, t;
SF(t)
while (t--)
{
SF(n)
v.reserve(n);
while (n--) {
SF(x) SF(y)
v.emplace_back( x,y );
}
// custom comparitor
const auto comp = [](const pairs &lhs, const pairs &rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second > rhs.second);
};
sort(v.begin(), v.end(), comp);
for (const auto &p : v) {
PF(p.first) printf(" "); PF(p.second); printf("\n");
}
v.clear();
}
return 0;
}
A couple reasons why inserting into a set is slower than inserting into a vector and then sorting:
std::set implementations involve binary trees, usually red-black trees. See here for details.
Iterating over the range of elements in a std::set is much slower
Note that both methods require n allocations and require on the order of nlog(n) operations for insertion + sorting.
I have to find min absolute difference between two elements of unsorted arrays.
My approach is to first sort both the array, run a loop over one array and find lower bound of each element of this array in another array.
And then check whether it is minimum or not and store it for further comparisons
Test Case:
2
8 1 3 5 7 9 7 3 1
8 2 4 6 8 10 8 6 2
8 2 3 5 10 9 3 2 1
7 1 2 6 12 13 3 2
Output :
1
0
result : passed
Explanation:
1) min will be abs(a[7]-b[7])
2) min will be abs(a[0]-b[(1)])
But when i am submitting to spoj I am getting wrong answer ,it look like I am missing some thing else .
problem https://www.spoj.com/problems/ACPC11B/
Please help where I am doing wrong?
My code:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector <int> a;
vector <int> b;
int main(){
int t;
cin>>t;
while(t--){
int na;
cin>>na;
for(int i=0;i<na;i++){
int temp;
cin>>temp;
a.push_back(temp);
}
int nb;
cin>>nb;
for(int i=0;i<nb;i++){
int temp;
cin>>temp;
b.push_back(temp);
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
int ans=a[0]-b[0];
for(int i=0;i<a.size();i++){
int bval = lower_bound(b.begin(),b.end(),a[i])-b.begin();
ans = min(ans,abs(a[i]-b[bval]));
if(bval>0)
ans = min(ans,abs(a[i]-b[bval-1]));
}
cout<<ans<<endl;
a.clear();
b.clear();
}
}
Your version has several issues:
a[0]-b[0] which might be negative, invalidating remaining computation.
lower_bound which might result in b.end() leading to out of bound access.
You can do something like the following:
std::size_t min_distance(std::vector<int> v1, std::vector<int> v2)
{
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
auto it1 = v1.begin();
auto it2 = v2.begin();
auto min = std::abs(*it1 - *it2);
while (min != 0 && it1 != v1.end() && it2 != v2.end()) {
min = std::min(min, std::abs(*it1 - *it2));
if (*it1 < *it2) {
++it1;
} else /*if (*it2 <= *it1)*/ {
++it2;
}
}
return min;
}
Demo
Is there some equivalent library or function that will give me the next combination of a set of values like next_permutation in does for me?
Combinations: from Mark Nelson's article on the same topic we have next_combination http://marknelson.us/2002/03/01/next-permutation
Permutations: from STL we have std::next_permutation
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
I am not aware of one. The basic idea is to represent your elements as a bit array. So for example, you have the set S:
S = {a, b, c}
[i, j, k] // a is the first bit, b is the second bit, c is the third bit
To generate the Power Set of S(just generate all numbers that are of size == 3 bits by using the simple addition):
000 // {}
001 // {c}
010 // {b}
011 // {b, c}
100 // {a}
101 // {a, c}
110 // {a, b}
111 // {a, b, c}
All what you have to do is to find what bits are set, and to relate them to your set's elements.
On final note, there is one combination you can produce when you want all elements to be used and that combination is the set it self, because in combinations the order doesn't matter so for sure we are talking about a number of elements n where 0 <= n <= size(S)
I've used this library when I've needed to do this. It has an interface very similar to std::next_permutation so it will be easy to use if you've used that before.
Enumeration of the powerset (that is, all combinations of all sizes) can use an adaptation of the binary increment algorithm.
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.)
}
The requirement of a bidirectional iterator is unfortunate, and could be worked around.
I was going to make it handle identical elements (multisets), but I need to go to bed :v( .
Usage:
#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;
}
}
EDIT: Here is the version for multisets. The set doesn't have to be sorted but identical elements do have to be grouped together.
#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;
}
}
Output:
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
Googling for C++ "next_combination" turned up this.
search from "mid" backwards until you find an element that is smaller
than *(end - 1). This is the element
we should increment. Call this
"head_pos".
search from "end" backwards until you find the last element that is
still larger than *head_pos. Call it
"tail_pos".
swap head_pos and tail_pos. Re-order the elements from [head_pos + 1, mid[
and [tail_pos + 1, end[ in increasing
order.
In case You have no choice, but to implement Your own function maybe this horror can help a bit or maybe other horrors among answers to that question.
Algorithm to return all combinations of k elements from n
I wrote it some time ago and the full picture eludes me now :), but the basic idea is this:
You have the original set and current combination is a vector of iterators to the elements selected. To get the next combination, You scan your set from right to left looking for a "bubble". By "bubble" I mean one or more adjacent elements not selected. The "bubble" might be immediately at the right. Then, in Your combination, You exchange the first element at the left of the "bubble" and all other elements from the combination, that are to the right in the set, with a subset of adjacent elements that starts at the beginning of the "bubble".