Question

I am writing a function kind of mimicking unordered_tuple from the sage combinatorial functions available in python.

It differs, though, in that the input set I am using is always [10, 9, 8, 7, 6], and only the number of entry varies (not larger than 10).

So, the desired output for entry = 3 and for entry = 4 is,

unordered_tuples([10,9,8,7,6], 3)
[[6, 6, 6],
 [6, 6, 7],
 [6, 6, 8],
 [6, 6, 9],
 [6, 6, 10],
 [6, 7, 7],
 [6, 7, 8],
 [6, 7, 9],
 [6, 7, 10],
 [6, 8, 8],
 [6, 8, 9],
 [6, 8, 10],
 [6, 9, 9],
 [6, 9, 10],
 [6, 10, 10],
 [7, 7, 7],
 [7, 7, 8],
 [7, 7, 9],
 [7, 7, 10],
 [7, 8, 8],
 [7, 8, 9],
 [7, 8, 10],
 [7, 9, 9],
 [7, 9, 10],
 [7, 10, 10],
 [8, 8, 8],
 [8, 8, 9],
 [8, 8, 10],
 [8, 9, 9],
 [8, 9, 10],
 [8, 10, 10],
 [9, 9, 9],
 [9, 9, 10],
 [9, 10, 10],
 [10, 10, 10]]

unordered_tuples([10,9,8,7,6], 4)
[[6, 6, 6, 6],
 [6, 6, 6, 7],
 [6, 6, 6, 8],
 [6, 6, 6, 9],
 [6, 6, 6, 10],
 [6, 6, 7, 7],
 [6, 6, 7, 8],
 [6, 6, 7, 9],
 [6, 6, 7, 10],
 [6, 6, 8, 8],
 [6, 6, 8, 9],
 [6, 6, 8, 10],
 [6, 6, 9, 9],
 [6, 6, 9, 10],
 [6, 6, 10, 10],
 [6, 7, 7, 7],
 [6, 7, 7, 8],
 [6, 7, 7, 9],
 [6, 7, 7, 10],
 [6, 7, 8, 8],
 [6, 7, 8, 9],
 [6, 7, 8, 10],
 [6, 7, 9, 9],
 [6, 7, 9, 10],
 [6, 7, 10, 10],
 [6, 8, 8, 8],
 [6, 8, 8, 9],
 [6, 8, 8, 10],
 [6, 8, 9, 9],
 [6, 8, 9, 10],
 [6, 8, 10, 10],
 [6, 9, 9, 9],
 [6, 9, 9, 10],
 [6, 9, 10, 10],
 [6, 10, 10, 10],
 [7, 7, 7, 7],
 [7, 7, 7, 8],
 [7, 7, 7, 9],
 [7, 7, 7, 10],
 [7, 7, 8, 8],
 [7, 7, 8, 9],
 [7, 7, 8, 10],
 [7, 7, 9, 9],
 [7, 7, 9, 10],
 [7, 7, 10, 10],
 [7, 8, 8, 8],
 [7, 8, 8, 9],
 [7, 8, 8, 10],
 [7, 8, 9, 9],
 [7, 8, 9, 10],
 [7, 8, 10, 10],
 [7, 9, 9, 9],
 [7, 9, 9, 10],
 [7, 9, 10, 10],
 [7, 10, 10, 10],
 [8, 8, 8, 8],
 [8, 8, 8, 9],
 [8, 8, 8, 10],
 [8, 8, 9, 9],
 [8, 8, 9, 10],
 [8, 8, 10, 10],
 [8, 9, 9, 9],
 [8, 9, 9, 10],
 [8, 9, 10, 10],
 [8, 10, 10, 10],
 [9, 9, 9, 9],
 [9, 9, 9, 10],
 [9, 9, 10, 10],
 [9, 10, 10, 10],
 [10, 10, 10, 10]]

and the c++ function I wrote follows.

I am actually not an experienced programmer, and I just tried to come up with the right solution, but it is working correctly, but it gives a lot of repetitive solutions.

Honestly, I wrote the function, but I don't even know what I wrote.

I could use set, but it would be very inefficient and I want to know the correct solution for this problem.

Can anyone fix it so that it gives the output above?

    #include<iostream>
    #include<string>
    #include<cstdlib>
    #include<vector>

    using namespace std;

    vector<vector<int> > ut(int);

    int main(int argc, char** argv) {
        int entry = atoi(argv[1]);
        ut(entry);
        return 1;
    }

    vector<vector<int> > ut(int entry) {
        vector<vector<int> > ret;

        int upper = 10;
        vector<int> v(entry, upper);
        ret.push_back(v);

        typedef vector<int>::iterator iter_t;

        iter_t it = v.begin();
        int count=0;
        int c = 0;
        while(v.back() != 6) {
            v = ret[count+c];
            while(it != v.end()) {
                --(*it);
                ++it;
                ret.push_back(v);
                ++c;
            }
            it = v.begin();
            c=0;
            ++count;
        }


        for(int i=0; i<ret.size(); ++i) {
            vector<int> tuple = ret[i];
            for(int j=0; j<tuple.size(); ++j) {
                cout << tuple[j] << ' ';
            }
            cout<<endl;
        }
        cout << endl;
        return ret;
    }
Was it helpful?

Solution

Look here:

vector<vector<int> > ret;

int upper = 10;
vector<int> v(entry, upper);
ret.push_back(v);

typedef vector<int>::iterator iter_t;

iter_t it = v.begin();
int count=0;
int c = 0;
while(v.back() != 6) {
  v = ret[count+c];
  while(it != v.end()) {
    --(*it);
    ++it;
    ret.push_back(v);
    ++c;
  }
  it = v.begin();
  c=0;
  ++count;
}

This is just scary. (I understand that you're a beginner; please understand that my criticism is intended to help.) Usually this kind if dense complexity is unnecessary and serves as a hiding place for bugs. Notice that c and it are set before the loop and at the end of the loop, and never used again; we can set them at the beginning of the loop, and the code will be shorter and clearer:

int count=0;
while(v.back() != 6) {
  iter_t it = v.begin();
  int c = 0;
  v = ret[count+c];
  while(it != v.end()) {
    --(*it);
    ++it;
    ret.push_back(v);
    ++c;
  }
  ++count;
}

Now we can see that c is never used except when it's zero. (Look at the original code if you don't believe me.) But what's much worse is that it points into v, and then v is assigned a new value. So it probably points into dead memory, and dereferencing it causes undefined behavior. And it's not clear how this code is intended to work anyway.

Try this:

vector<int> v(n,6);

vector<int>::iterator itr1;
do{
  ret.push_back(v);

  itr1 = v.begin();

  while(++(*itr1)>10){
      if(++itr1==v.end())
        break;
  }
  for(vector<int>::iterator itr2 = v.begin(); itr2!=itr1; ++itr2)
    *itr2 = *itr1;
}
while(itr1!=v.end());

OTHER TIPS

A good place to start with permutation problems is recursion. Taking this approach, to build all the outputs of length 3, you choose a digit from your set [6, 7, 8, 9, 10], and then append to it all the outputs of length 2, with the input set constrained to start from the digit chosen. So, if, e.g. you chose 7, your input set for the first recursive call would be [ 7, 8, 9, 10]. I.e., the recursive call in this case would be append to [ 7 ] all outputs of length 2 from the input [ 7, 8, 9, 10]

A program that implements this idea is below. I'd be interested to see if anyone can come up with a non-recursive solution.

#include "stdafx.h"
#include <iostream>
#include <vector>

typedef std::vector<int> intvec;
typedef std::vector<intvec> intvecs;

void GenerateUnOrderedIntVecs(
    const int* remainingInput, int remainingInputLen, 
    const intvec& outputSoFar, int remainingOutputLen,
    intvecs& output)
{
    if (remainingOutputLen == 0) { // base case of recursion
        output.push_back(outputSoFar);
        return;
    }

    // For all digits in our input
    for(int i=0; i<remainingInputLen; ++i) {
        // Add the ith digit to our output so far
        intvec outputSoFar2(outputSoFar);
        outputSoFar2.push_back(remainingInput[i]);
        // The recursion
        GenerateUnOrderedIntVecs(
            remainingInput + i,    // input set constrained to start from chosen digit
            remainingInputLen - i, // input set is shorter
            outputSoFar2,          // one digit longer than the parameter outputSoFar
            remainingOutputLen -1, // so we need one digit less as we recurse
            output);
    }
}

int main(int argc, _TCHAR* argv[])
{
    const int nToChooseFrom = 5;
    const int nToChooose = 3;
    const int input[nToChooseFrom] = { 6, 7, 8, 9, 10 }; // provide input in sorted order (or sort it!)

    intvecs output;
    GenerateUnOrderedIntVecs(
        input, nToChooseFrom,
        intvec(), nToChooose,
        output);

    for(intvecs::const_iterator i=output.begin(); i!=output.end(); ++i) {
        std::cout << "[ ";
        const intvec& unordered_tuple = *i;
        for(intvec::const_iterator j = unordered_tuple.begin(); j!=unordered_tuple.end(); ++j) {
            std::cout << *j << " ";
        }
        std::cout << "]\n";
    }

    return 0;
}

It seems to work on both your examples (but I only checked the first thoroughly). If you can't see how it works by reading the code, a good approach would be to run it in a debugger (that's what I had to do to get it to work!:)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top