3

at the moment I have the following code:

for(int i = 0; i < 4; i++){
    cout << rowNo[i] << endl;
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        cout << rowNo[i] << '.';
        cout << rowNo[j] << endl;
    }
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        for(int k = 0; k < 4; k++){
            cout << rowNo[i] << '.';
            cout << rowNo[j] << '.';
            cout << rowNo[k] << endl;
        }
    }
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        for(int k = 0; k < 4; k++){
            for(int l = 0; l < 4; l++){
                cout << rowNo[i] << '.';
                cout << rowNo[j] << '.';
                cout << rowNo[k] << '.';
                cout << rowNo[l] << endl;
            }
        }
    }
}

Where rowNo[] is an array {1,2,3,4}

And I was wondering two things:

  1. Can this be simplified, so maybe put into some sort of recursive loop?
  2. Following that, can this then be made for an array of size N?
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    printing every permutation of every set in the powerset of {1,2,3,4}? – UmNyobe Dec 02 '15 at 09:56
  • Possible duplicate of [Getting ALL permutations of ALL sublists of a list of integers](http://stackoverflow.com/questions/31124912/getting-all-permutations-of-all-sublists-of-a-list-of-integers) – ashiquzzaman33 Dec 02 '15 at 09:58
  • 1
    hum actually 4444 is valid. So you just want every number possible with the alphabet {1,2,3,4} – UmNyobe Dec 02 '15 at 09:59
  • Yeah basically, although the way in which the output is formatted is not really a problem. So to output for example: 1, 2, 3, 4, 1.1, 1.2, 1.3, 1.4... – user2506322 Dec 02 '15 at 10:02
  • I'd approach this as printing values of the array indexed by the digits of all N-digit base-4 numbers. I might come up with some code in spare time - but you probably can do it yourself :) – Rostislav Dec 02 '15 at 10:12

4 Answers4

3

Your looking for Cartesian_product

With

bool increment(std::vector<std::size_t>& v, std::size_t maxSize)
{
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        ++*it;
        if (*it != maxSize) {
            return true;
        }
        *it = 0;
    }
    return false;
}

then you can do:

void print_cartesian_product(const std::vector<int>&v, int n)
{
    std::vector<std::size_t> indexes(n);

    do {
        print(v, indexes);
    } while (increment(indexes, v.size()));

}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

First solution it comes my mind is that on every loop to put in a buffer and finally to print all the buffers. I think there are some other ingenious methods

for(int i = 0; i < 4; i++){
        put in buffer1 rowNo[i]
        for(int j = 0; j < 4; j++){
            put in buffer2 rowNo[i],rowNo[j]
            for(int k = 0; k < 4; k++){
                 put in buffer3 rowNo[i],rowNo[j],rowNo[k]
                for(int l = 0; l < 4; l++){
                    put in buffer4 rowNo[i],rowNo[j],rowNo[k],rowNo[l],endl.
                }
            }
        }
    }
     print(buffer1);
     print(buffer2);
     print(buffer3);
     print(buffer4);
MSD561
  • 512
  • 5
  • 16
  • Also specific for your request you could generate the code and then build it. What you have to do is to make a program that write 'for' n times, then you build it. If you wish to try this approach tell me. – MSD561 Dec 02 '15 at 10:10
1

You are actually trying to print a number encoded in base4 with digit {1, 2, 3, 4}. To achieve it, You only need to define a function to increment by one. I propose a generic solution in the term of amount of number to print and base. Like others, I use a number to mean "empty digit", and I use zero which is quite convenient.

Complete source code :

#include <iostream>
#include <vector>

bool increment_basep(std::vector<int>& number, int p)
{ 
    int i = 0; 
    while(i < number.size() && number[i] == p)
    { 
       number[i] = 1;
       ++i;
    }
    if(i >= number.size())
        return false;

    ++number[i];
    return true;
}

void print_vect(std::vector<int>& number)
{
   for(int i = number.size() -1 ; i >= 0; --i)
   {
       if(number[i] != 0)
          std::cout << number[i];
   }
   std::cout << std::endl;
}

int main() {
    int n = 4;
    int p = 4;
    std::vector<int> num4(n);
    std::fill(num4.begin(), num4.end(), 0);

    while(increment_basep(num4, p))
    {
        print_vect(num4);
    }
    return 0;
}

The increment return whether or not the computation has overflown. When we overflow we know we need to stop.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
0

The following is the simplest code I came up with. There has to be a more direct way of doing this though...

It basically introduces a "ghost" index -1, corresponding to an empty place in a number. The ternary operators in the loops conditions are there to avoid duplicates.

int main()
{
    int N = 4;
    int rowNo[4] = {1, 2, 3, 4};

    for (int i = -1; i < N; i++)
        for (int j = (i > -1 ? 0 : -1); j < N; j++)
            for (int k = (j > -1 ? 0 : -1); k < N; k++)
                for (int l = (k > -1 ? 0 : -1); l < N; l++)
                {
                    if (i > -1) std::cout << rowNo[i] << '.';
                    if (j > -1) std::cout << rowNo[j] << '.';
                    if (k > -1) std::cout << rowNo[k] << '.';
                    if (l > -1) std::cout << rowNo[l];
                    std::cout << std::endl;
                }
}

It can of course be generalized to an array of arbitraty size, possibly with some code generation script.

BlackDwarf
  • 2,070
  • 1
  • 17
  • 22
  • This is hardly an improvement over OP's code. It also uses 4 nested loops, so it's just as fast (or slow), but it's harder to read and understand. Besides, I'm not sure he wants to avoid duplicates. And you are missing the point about size N. Your approach, just like his, requires code to be added for every extra item. With 4 elements you need to write 4 loops. The OP wants code that works for any value of N without touching the rest of the code. – Fabio says Reinstate Monica Dec 02 '15 at 10:17
  • Thank you, this works as intended. However if N were to be inputted by user at the beginning, is it possible to create a dynamic amount of for loops? N in this case will have a max of 8. – user2506322 Dec 02 '15 at 10:19
  • 1
    @FabioTurati I'm afraid the complexity of printing all the combinations of a set with k elements will always be O(n^k), regardless of the way we write the code :) And the OP didn't print the same combination twice in his original code, so mine had to do the same. – BlackDwarf Dec 02 '15 at 10:59
  • @DeepBlackDwarf Sorry, I didn't express myself correctly. What I meant is that your algorithm is harder to understand than the OP's, without satisfying his request to make it work for any N, nor providing any other benefit. Speed was just meant as an example of the benefits that I would *in general* expect from a different algorithm; I was not implying that in this specific case it can be done. So in my opinion it doesn't make sense to adopt this solution. True, it's an elegant approach, and it's shorter; but in my opinion neither of these compensates the loss of readability. – Fabio says Reinstate Monica Dec 03 '15 at 00:19