how to avoid this for-loop mess in c++? - c++

I need to program all possible sets of numbers from 1 to N for an arbitrary number m of integers without permutation.
Since I don't know how to explain it better here are some examples:
for m = 2
vector<vector<int>> box;
int N = 5;
for(int i = 1; i <= N; i++) {
for(int j = N; j >= i; j--) {
vector<int> dummy;
dummy.push_back(i);
dummy.push_back(j);
box.push_back(dummy);
}
}
for m = 3
vector<vector<int>> box;
int N = 5;
for(int i = 1; i <= N; i++) {
for(int j = N; j >= i; j--) {
for(int k = N; k >= j; k--) {
vector<int> dummy;
dummy.push_back(i);
dummy.push_back(j);
dummy.push_back(k);
box.push_back(dummy);
}
}
}
This works perfectly fine and the result is what I need. But like already mentioned, m can be arbitrary and I can't be bothered to implement this for m = 37 or what ever. N and m are known values but change while the program is running. There must be a better way to implement this than for the m = 37 case to implement a row of 37-for-loops. Can someone help me? I'm kind a clueless :\
edit: to explain better what I'm looking for here are some more examples.
Let's say N = 5 and m = 4, than 1223 is a feasible solution for me, 124 is not since it is to short. Let's say I already found 1223 as a solution, than I don't need 2123, 2213 or any other permutation of this number.
edit2: Or if you prefer a more visual (mathematical?) problem formulation here you go.
Consider m the dimension. With m been 2 you are left with a N size Matrix. I am looking for the upper (or lower) triangle of this Matrix including the diagonal. Let's move to m = 3, the Matrix becomes a 3 dimensional cube (or Tensor if you so wish), now I'm looking for the upper (or lower) tetrahedron including the diagonal-plain. For higher dimensions than 3 I'm looking for the hyper-tetrahedron of the hyper-cube including the hyper-diagonal-plane.

http://howardhinnant.github.io/combinations.html
The following generic algorithms permit a client to visit every combination or permuation of a sequence of length N, r items at time.
Example usage:
std::vector<std::vector<int>> box;
std::vector<int> v(N);
std::iota(begin(v), end(v), 1);
for_each_combination(begin(v), begin(v) + M, end(v), [](auto b, auto e) {
box.emplace_back(b, e);
return false;
});
The above code just shows inserting each combination into box as an example, but you probably don't want to actually do that: assuming that box is simply an intermediary and that your actual work then uses it somewhere else, you can avoid an intermediary and simply do whatever work you need directly in the body of the functor.
Here's a complete, working example using code from the provided link.
Since what you want is combinations with repetition rather than just combinations. Here's an example of implementing this on top of for_each_combination():
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> indices;
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
indices.clear();
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
indices.push_back(current_element);
++b;
} else {
++current_element;
}
}
func(begin(indices), end(indices));
return false;
});
}
The wikipedia article on combinations shows a good illustration of what this is doing: it's getting all the combinations (without repetition) of numbers [0, N + M - 1) and then looking for the 'gaps' in the results. The gaps represent transitions from repetitions of one element to repetitions of the next.
The functor you pass to this algorithm is given a range that contains indices into a collection containing the elements you're combining. For example if you want to get all sets of three elements from the set of {x,y}, the results are you want are {{x,x,x}, {x,x,y}, {x,y,y}, {y,y,y}}, and this algorithm represents this by returning ranges of indices into the (ordered) set {x,y}: {{0,0,0}, {0,0,1}, {0,1,1}, {1,1,1}}.
So normally to use this you have a vector or something containing your elements and use the ranges produced by this algorithm as indices into that container. However in your case, since the elements are just the numbers from 1 to N you can use the indices directly by adding one to each index:
for_each_combination_with_repetition(N, M, [&](auto b, auto e) {
for(; b != e; ++b) {
int index = *b;
std::cout << index + 1 << " ";
}
std::cout << '\n';
});
Complete example
An alternative implementation can return vectors that represent counts of each category. E.g. the earlier {{x,x,x}, {x,x,y}, {x,y,y}, {y,y,y}} results could be represented by: {{3,0} {2,1},{1,2}, {0,3}}. Modifying the implementation to produce this representation instead looks like this:
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> repetitions(categories);
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
std::fill(begin(repetitions), end(repetitions), 0);
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
++repetitions[current_element];
++b;
} else {
++current_element;
}
}
func(begin(repetitions), end(repetitions));
return false;
});
}

You can use recursion to find all subsets. This can probably be improved stylistically, but here is a quick take at the problem:
std::vector<std::set<int>> subsets(std::vector<int> x)
{
if (x.size() == 0)
return { std::set<int>() };
else
{
int last = x.back();
x.pop_back();
auto sets = subsets(x);
size_t n = sets.size();
for (size_t i = 0; i < n; i++)
{
std::set<int> s = sets[i];
s.insert(last);
sets.push_back(std::move(s));
}
return sets;
}
}
This doubles the number of answers at each recursion step : the number of subsets is 2^n, as expected.
You can substitute std::set for std::vector if you wish.

Related

Can I get rid of nested for loops here?

I have a function that takes a vector and returns a vector by combining all the elements in it. Right now, I have 3 nested for loops that create a combination that is 3 levels deep. I would like it to look better and have the ability to add the functionality to make it 4 levels deep when I want.
If input = ["one", "two", "three"]
3 level output = "onetwothree" "twoonethree" and so on.
std::vector<std::string> generator(std::vector<std::string>& x)
{
std::vector<std::string> output;
std::string tmp;
for (auto i : x) {
output.push_back(i);
for (auto j : x) {
tmp = i + j;
output.push_back(tmp);
for (auto k : x) {
tmp = i + j + k;
output.push_back(tmp);
}
}
}
return output;
}
I have looked into iterators, but I can't figure out if it would work.
If what you are looking for is to simply generate the permutations of all the elements of the string vector x and store these permutations into another output vector, this is easily accomplished by using std::next_permutation and std::accumulate:
#include <vector>
#include <string>
#include <numeric>
#include <iostream>
#include <algorithm>
std::vector<std::string> generator(std::vector<std::string> x)
{
std::vector<std::string> output;
std::sort(x.begin(), x.end());
do
{
output.push_back(std::accumulate(x.begin(), x.end(), std::string()));
} while (std::next_permutation(x.begin(), x.end()));
return output;
}
int main()
{
auto v = generator({"one","two","three"});
for (auto& val : v)
std::cout << val << "\n";
}
Live Example
The std::accumulate basically calls operator + on the elements by default, thus the string is automatically concatenated.
As far as std::next_permutation, the description of what it does is explained at the link. Basically you want to start out with a sorted sequence, and call std::next_permutation to get the next permutation of elements.
Note that this is not contingent of the number of "levels" (as you call it). You could have a vector of 10 strings, and this would work correctly (assuming there are no memory constraints).
If you want to generate all combinations of N words with max length L you could use this:
std::vector<std::string> generator(const std::vector<std::string> & x, int levels) {
int nWords = x.size();
std::vector<std::string> output;
for (int l = 1; l <= levels; ++l) {
int nCombs = std::pow(nWords, l);
for (int i = 0; i < nCombs; ++i) {
std::string cur;
for (int j = 0, k = i; j < l; ++j) {
cur += x[k%nWords];
k /= nWords;
}
output.push_back(cur);
}
}
return output;
}
Live Example
There are still 3 nested loops, but this works for any value of L - not just 3. L > N also works.
Hi I had the similar problem in Python once.
The goal I suppose is to have a "n-nested" loops such that n is a variable. A better result would be to make each index I_i of level i be variables. That is to say, given a list [I_1,I_2,...,I_n], you should be able to generate such loop
for i_1 in range( I_1):
for i_2 in range( I_2):
...
for i_n in range(I_n):
some_function(i_1,i_2,...,i_n)
One way to do this is to use mathematics. You can build a number such that on the ith digit, it's I_i based. This number's maxmium value is just I_1*I_2*...*I_n. In this way, the entire loop will be collaped into one simple loop
for i in range(I_1*I_2*...*I_n):
# obtain these numbers
i_1 = f_1(i)
i_2 = f_2(i)
...
i_n = f_n(i)
some_function(i_1,i_2,...,i_n)
Although the functions to obtain the is are a bit complicated.
Another way to do it is, as you have mentioned, iterators. In Python it's just import itertools. In C++, however, I found this cppitertools. I haven't tried it, but I suppose this could work.
Still, if you want speed, the first approch is preferred. Still, I think there are better solutions.

Solution for maximum xor secondary in an array of integers

I am trying to solve this codeforces problem
http://codeforces.com/contest/281/problem/D
Given an array of integers, find the maximum xor of the first and second max element in any of the sub sequences ?
I am not able to figure out the optimal approach to solve this problem. Few of the solving techniques I articulated was using sorting, stack but I could not figure out the right solution.
I googled and found out the problem setter's code for the solution. But I could not understand the solution as it is in c++ and I am naive to it.
Below is the problem setter's code in c++
using namespace std;
using namespace io;
typedef set<int> Set;
typedef set<int, greater<int> > SetRev;
namespace solution {
const int SIZE = 100000 + 11;
int n;
int A[SIZE];
II S[SIZE];
Set P;
SetRev P_rev;
int result;
}
namespace solution {
class Solver {
public:
void solve() {
normalize();
result = get_maximum_xor();
}
int get_maximum_xor() {
int res = 0;
for (int i = 0; i < n; i++) {
int current_value = S[i].first;
Set::iterator it_after = P.upper_bound(S[i].second);
Set::iterator it_before = P_rev.upper_bound(S[i].second);
if (it_after != P.end()) {
int after_value = A[*it_after];
res = max(res, current_value ^ after_value);
}
if (it_before != P_rev.end()) {
int before_value = A[*it_before];
res = max(res, current_value, before_value);
}
P.insert(S[i].second);
P_rev.insert(S[i].second);
}
return res;
}
void normalise() {
for (int i = 0; i < n; i++) {
S[i] = II(A[i], i);
}
sort(S, S + n, greater<II>());
}
}
Can someone please explain me the solution, the approach used as I understand it in pieces and not totally ?
Ok, so Solver::solve() starts by calling normalise:
void normalise() {
for (int i = 0; i < n; i++) {
S[i] = II(A[i], i);
}
sort(S, S + n, greater<II>());
}
What that's doing is taking an array A of integers - say {4, 2, 9}, and populating an array S where A's values are sorted and paired with the index at which they appear in A - for our example, {{2, 1}, {4, 0}, {9, 2}}.
Then the solver calls get_maximum_xor()...
for (int i = 0; i < n; i++) {
int current_value = S[i].first;
Set::iterator it_after = P.upper_bound(S[i].second);
Set::iterator it_before = P_rev.upper_bound(S[i].second);
The "for i" loop is used to get successive sorted values from S (those values originally from A). While you haven't posted a complete program, so we can't know for sure nothing's prepopulating any values in P, I'll assume that. We do know P's is a std::map and upper_bound searches to find the first element in P greater than S[i].second (the index at which current_value appeared in A) and values above, then something similar for P_rev which is a std::map in which values are sorted in descending order, likely it will be kept populated with the same values as P but again we don't have the code.
Then...
if (it_after != P.end()) {
int after_value = A[*it_after];
res = max(res, current_value ^ after_value);
}
...is saying that if any of the values in P were >= S[i].second, look up A at the index it_after found (getting a sense now that P tracks the last elements in each subsequence (?)), and if the current_value XORed with that value from A is more than any earlier result candidate (res), then update res with the new larger value.
It does something similar with P_rev.
Finally...
P.insert(S[i].second);
P_rev.insert(S[i].second);
Adds the index of current_value in A to P and P_rev for future iterations.
So, while I haven't explained why or how the algorithm works (I haven't even read the problem statement), I think that should make it clear what the C++ is doing which is what you said you're struggling with - you're on your own for the rest ;-).

Problems with vectors, how to remove the arrays in my vectors?

I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).

Find order of an array using minimum memory and time

Let's say i have an array of 5 elements. My program knows it's always 5 elements and when sorted it's always 1,2,3,4,5 only.
As per permutations formula i.e n!/(n-r)! we can order it in 120 ways.
In C++ using std::next_permutation I can generate all those 120 orders.
Now, my program/routine accepts an input argument as a number in the range of 1 to 120 and gives the specific order of an array as output.
This works fine for small array sizes as i can repeat std::next_permutation until that matches input parameter.
The real problem is, How can i do it in less time if my array has 25 elements or more? For 25 elements, the number of possible orders are : 15511210043330985984000000.
Is there a technique that I can easily find the order of numbers using a given number as input?
Thanks in advance :)
This is an example c++ implementation of the algorithm mentioned in this link:
#include <vector>
#define ull unsigned long long
ull factorial(int n) {
ull fac = 1;
for (int i = 2; i <= n; i++)
fac *= i;
return fac;
}
std::vector<int> findPermutation(int len, long idx) {
std::vector<int> original = std::vector<int>(len);
std::vector<int> permutation = std::vector<int>();
for (int i = 0; i < len; i++) {
original[i] = i;
}
ull currIdx = idx;
ull fac = factorial(len);
while (original.size() > 0) {
fac /= original.size();
int next = (currIdx - 1) / fac;
permutation.push_back(original[next]);
original.erase(original.begin() + next);
currIdx -= fac * next;
}
return permutation;
}
The findPermutation function accepts the length of the original string and the index of the required permutation, and returns an array that represents that permutation. For example, [0, 1, 2, 3, 4] is the first permutation of any string with length 5, and [4, 3, 2, 1, 0] is the last (120th) permutation.
I have had a similar problem where I was storing lots of row in a Gtk TreeView and did not want to go over all of them every time I want to access a row by its position and not by its reference.
So, I created a map of the positions of the row so I could easily identify them by the parameter I needed.
So, my suggestion to this is you go over all permutations once and map every std::permutation in an array (I used a std::vector), so you can access it by myVector[permutation_id].
Here is my way I have done the mapping:
vector<int> FILECHOOSER_MAP;
void updateFileChooserMap() {
vector<int> map;
TreeModel::Children children = getInterface().getFileChooserModel()->children();
int i = 0;
for(TreeModel::Children::iterator iter = children.begin(); iter != children.end(); iter++) {
i++;
TreeModel::Row row = *iter;
int id = row[getInterface().getFileChooserColumns().id];
if( id >= map.size()) {
for(int x = map.size(); x <= id; x++) {
map.push_back(-1);
}
}
map[id] = i;
}
FILECHOOSER_MAP = map;
}
So in your case you would just iterate over the permutations like this and you can map them in a way that allows you accesing them by their id.
I hope this helps you :D
regards, tagelicht

How can I create an array with Fibonacci numbers up to a certain integer n?

So for an assignment I've been asked to create a function that will generate an array of fibonacci numbers and the user will then provide an array of random numbers. My function must then check if the array the user has entered contains any fibonacci numbers then the function will output true, otherwise it will output false. I have already been able to create the array of Fib numbers and check it against the array that the user enters however it is limited since my Fib array has a max size of 100.
bool hasFibNum (int arr[], int size){
int fibarray[100];
fibarray[0] = 0;
fibarray[1] = 1;
bool result = false;
for (int i = 2; i < 100; i++)
{
fibarray[i] = fibarray[i-1] + fibarray[i-2];
}
for (int i = 0; i < size; i++)
{
for(int j = 0; j < 100; j++){
if (fibarray[j] == arr[i])
result = true;
}
}
return result;
}
So basically how can I make it so that I don't have to use int fibarray[100] and can instead generate fib numbers up to a certain point. That point being the maximum number in the user's array.
So for example if the user enters the array {4,2,1,8,21}, I need to generate a fibarray up to the number 21 {1,1,2,3,5,8,13,21}. If the user enters the array {1,4,10} I would need to generate a fibarray with {1,1,2,3,5,8,13}
Quite new to programming so any help would be appreciated! Sorry if my code is terrible.
It is possible that I still don't understand your question, but if I do, then I would achieve what you want like this:
bool hasFibNum (int arr[], int size){
if (size == 0) return false;
int maxValue = arr[0];
for (int i = 1; i < size; i++)
{
if (arr[i] > maxValue) maxValue = arr[i];
}
int first = 0;
int second = 1;
while (second < maxValue)
{
for (int i = 0; i < size; i++)
{
if (arr[i] == first) return true;
if (arr[i] == second) return true;
}
first = first + second;
second = second + first;
}
return false;
}
Here is a function that returns a dynamic array with all of the Fibonacci numbers up to and including max (assuming max > 0)
std::vector<size_t> make_fibs( size_t max ) {
std::vector<size_t> retval = {1,1};
while( retval.back() < max ) {
retval.push_back( retval.back()+*(retval.end()-2) );
}
return retval;
}
I prepopulate it with 2 elements rather than keeping track of the last 2 separately.
Note that under some definitions, 0 and -1 are Fibonacci numbers. If you are using that, start the array off with {-1, 0, 1} (which isn't their order, it is actually -1, 1, 0, 1, but by keeping them in ascending order we can binary_search below). If you do so, change the type to an int not a size_t.
Next, a sketch of an implementation for has_fibs:
template<class T, size_t N>
bool has_fibs( T(&array)[N] ) {
// bring `begin` and `end` into view, one of the good uses of `using`:
using std::begin; using std::end;
// guaranteed array is nonempty, so
T m = *std::max_element( begin(array), end(array) ); will have a max, so * is safe.
if (m < 0) m = 0; // deal with the possibility the `array` is all negative
// use `auto` to not repeat a type, and `const` because we aren't going to alter it:
const auto fibs = make_fibs(m);
// d-d-d-ouble `std` algorithm:
return std::find_if( begin(array), end(array), [&fibs]( T v )->bool {
return std::binary_search( begin(fibs), end(fibs), v );
}) != end(array);
}
here I create a template function that takes your (fixed sized) array as a reference. This has the advantage that ranged-based loops will work on it.
Next, I use a std algorithm max_element to find the max element.
Finally, I use two std algorithms, find_if and binary_search, plus a lambda to glue them together, to find any intersections between the two containers.
I'm liberally using C++11 features and lots of abstraction here. If you don't understand a function, I encourage you to rewrite the parts you don't understand rather than copying blindly.
This code has runtime O(n lg lg n) which is probably overkill. (fibs grow exponentially. Building them takes lg n time, searching them takes lg lg n time, and we search then n times).