Reputation: 808
Suppose that we have k
sets each of which contains q
elements. I want to generate all possible sets in which we select exactly 1 element from each set. Assume that the sets are represented as a table where each row is a set and its columns are its elements. Also assume that all elements are indexed row-wise like this
Set 1: 1 2 3
Set 2: 4 5 6
Set 3: 7 8 9
The thing is that k,q may vary so I cannot use nested for loops. I work in C++ and this structure is actually a std::vector
of std::vector
of int
, but I am not asking for code here, just an idea on how to do this.
Upvotes: 0
Views: 174
Reputation: 217478
A hard coded solution would be
for (int a1 : v[0]) {
for (int a2 : v[1]) {
for (int a3 : v[2]) {
for (int a4 : v[3]) {
for (int a5 : v[4]) {
do_job(a1, a2, a3, a4, a5);
}
}
}
}
}
To make it generic, you may do:
bool increase(const std::vector<std::set<int>>& v,
std::vector<std::set<int>::iterator>& it)
{
for (std::size_t i = 0, size = it.size(); i != size; ++i) {
const std::size_t index = size - 1 - i;
++it[index];
if (it[index] == v[index].end()) {
it[index] = v[index].begin();
} else {
return true;
}
}
return false;
}
template <typename F>
void iterate(const std::vector<std::set<int>>& v, F&& do_job)
{
std::vector<std::set<int>::iterator> its;
its.reserve(v.size());
for (auto& s : v) {
its.push_back(s.begin());
}
do {
do_job(its);
} while (increase(v, its));
}
Upvotes: 1
Reputation: 9117
Recursive
using sets = vector<vector<int>>;
void rec(int index, const sets& s, vector<int>& v) {
for (int next : s[index]) {
v[index] = next;
if (index + 1 == s.size()) {
output(v);
} else {
rec(index+1, s, v);
}
}
}
int main() {
sets s = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int q = s[0].size();
vector<int> v(q);
rec(0, s, v);
return 0;
}
Non recursive
The main idea is that every choice can be encoded by a number in base-q
numeral system. And all you need to do is to iterate through all base-q
numbers with length <= n
. Every digit of the number is an index in the corresponding set.
For example, we have 2 sets with 3 numbers. You need to iterate through {00, 01, 02, 10, 11, 12, 20, 21, 22}
.
using sets = vector<vector<int>>;
void non_rec(const sets& s) {
int q = s[0].size();
int k = s.size();
vector<int> v(q);
int cnt = (int)pow(q, k);
for (int i = 0; i < cnt; ++i) {
int tmp = i;
for (int j = 0; j < k; ++j) {
v[j] = s[j][tmp % q];
tmp /= q;
}
output(v);
}
}
int main() {
sets s = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
non_rec(s);
return 0;
}
Upvotes: 2
Reputation: 7542
You can use backtracking here to generate all subsets
void func(vector<vector<int> > arr,int row,vector<int> &temp,vector<vector<int> > &ans)
{
if(row>=arr.size())
{
ans.push_back(temp); //You have generated one of the answers.store it
return;
}
for(int i=0;i<arr[row].size();i++)
{
temp.push_back(arr[row][i]); //Pick an element from current set
func(arr,row+1,temp,ans); //recurse for next set
temp.pop_back(); //Remove from current set to include next element from this set(for loop)
}
}
Working code: http://ideone.com/RvHMNT
Upvotes: 0
Reputation: 21510
If you are unaware of the number of sets and of the number of elements in each set, then you can generate the set of all elements you want the following way. Basically, you can loop over all the elements of a set and include that in the previous remaining product of whatever had been computed so far. Let me know if something is still unclear
#include <iostream>
#include <set>
#include <tuple>
#include <vector>
using std::cout;
using std::endl;
void append_results(const std::set<int>& set,
std::vector<std::vector<int>>& results);
int main() {
auto sets = std::vector<std::set<int>>{
std::set<int>{1, 2, 3},
std::set<int>{4, 5, 6},
std::set<int>{7, 8, 9}
};
auto results = std::vector<std::vector<int>>{};
for (const auto& set : sets) {
append_results(set, results);
}
for (const auto& result : results) {
for (auto integer : result) {
cout << integer << " ";
}
cout << endl;
}
return 0;
}
void append_results(const std::set<int>& set,
std::vector<std::vector<int>>& results) {
if (results.empty()) {
for (auto integer : set) {
results.push_back(std::vector<int>{integer});
}
} else {
auto old_results = results;
results.clear();
for (auto integer : set) {
for (auto old_result : old_results) {
old_result.push_back(integer);
results.push_back(std::move(old_result));
}
}
}
}
Upvotes: 0
Reputation: 21160
This does the job?
std::vector<std::vector<int>> v;
for(auto& r : v)
for(auto i : r)
// use i
Upvotes: 0