-4

How can I generate all combinations of n elements in groups of k? For example, takig "abcd" in groups of 3, from [aaa] to [ddd]?

EDIT: What I've "accomplished" so far:

int main (int argc, char * argvc[]) {
    int tComb = 0, array[7] = { 48 , 48 , 48 , 48 , 48 , 48 , 48 };
    while ( tComb < atoi(argvc[1]) ) {
        for (int i = 6 ; i>0 ; i--) {
            if (array[i] == 58)
                array[i] = 65;
            if (array[i] == 91)
                array[i] = 97;
            if (array[i] == 123){
                array[i] = 48;
                array[i-1]++;
            }
        }
        std::cout << "Current Combination: ";
        std::cout << array;
        std::cout << "\n";
        tComb++;
        array[6]++;
    }
}

It'll try and generate backward the latest combination of alphanumeric characters, but it's hardcoded and won't work well.

Debianita
  • 108
  • 1
  • 8

3 Answers3

2

Am not sure but i think this is the answer to your question. If you want three groups than you should have 3 different loops.Its pretty simple when you see the output of this program. You just need to increment the value of what ever you want to generate there possible combination.

The below Code will generate all possible combination of "abcd" in groups of 3, from [aaa] to [ddd].

int main()
{
   char ch1;
   char ch2;
   char ch3;

    for(ch1='a';ch1<='d';ch1++)
    {
       for(ch2='a';ch2<='d';ch2++)
       {
            for(ch3='a';ch3<='d';ch3++)
            {
               printf("%c %c %c\n",ch1,ch2,ch3);
            }
            printf("\n"); //just to have clean and understandable output
       }
       printf("\n\n\n"); //just to have clean and understandable output
    }
 return 0;
}
Mysterious Jack
  • 621
  • 6
  • 18
  • That's just as hardcoded as the previous, what I want is to generate all combinations with repetitions of n elements with k in each group, not only of three elements in lenght but for more as well. – Debianita Apr 13 '14 at 15:28
  • 1
    @Debianita wow! am not good at maths ..:),i cant understand what you are trying to say, can you please post your expected output with some of your inputs here in this comment.I want to help you,your problem seems interesting. – Mysterious Jack Apr 13 '14 at 15:39
  • @Debianita: Can you take the above solution and expand on it or are you looking for somebody to write you the solution? – Thomas Matthews Apr 13 '14 at 17:42
  • It's not as easy as it seems, exapnding it like this means a loop inside a loop for each new element, wich is not good, since the program needs to accept any input and compute them from 1 to 100 if required.. – Debianita Apr 13 '14 at 19:36
2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

unsigned powu(unsigned base, unsigned exp){
    unsigned result = 1;
    while(exp > 0){
        if(exp & 1)
            result *= base;
        base = base * base;
        exp >>=1;
    }
    return result;
}

int main(int argc, char *argv[]){
    if(argc != 3){
        fprintf(stderr, "Usage : RepeatedPermutation abcd 3\n");
        return -1;
    }
    char *list = argv[1];
    unsigned gp_len = atoi(argv[2]);
    unsigned list_len = strlen(list);
    char *gp = calloc(gp_len+1, sizeof(char));
    int total_n = powu(list_len, gp_len);
    int i, j;
    for(i=0;i<total_n;++i){
        int n = i;
        for(j=0;j<gp_len;++j){
            gp[gp_len -j -1] = list[n % list_len];
            n /= list_len;
        }
        printf("[%s]\n", gp);
    }
    free(gp);
    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • Awesome, I'm marking this problem as solution since it does so. – Debianita Apr 13 '14 at 19:47
  • I've been trying to understand, but I cannot understand the inner loop.. Also To calculate the total possibilities shouldn't it be something like Factorial(n+k-1)/(Factorial(k)*Factorial(n-1)) ? – Debianita Apr 13 '14 at 21:43
  • @Debianita It has converted to a representation of the quaternary number is the inner loop. 000(4)~333(4:radix base). – BLUEPIXY Apr 13 '14 at 21:56
  • @Debianita also repeated permutation of when choosing k from n is n ^ k. – BLUEPIXY Apr 13 '14 at 22:02
  • Oh, I was reading this: http://es.wikipedia.org/wiki/Combinaciones_con_repetici%C3%B3n when I thought I've found the solution to the problem, I still don't understand the code but I've printed it to try and understand it. – Debianita Apr 13 '14 at 23:52
  • @Debianita , your Link is a combination that does not distinguish between [ada] and [aad]. my Answer distinguish. (So I heard for the first time in comment) – BLUEPIXY Apr 14 '14 at 08:01
1

One method to generate all the combinations is to treat this as a number counting program.

The Counting Algorithm
Let's take the case of "digits": a, b, c, and d.

The first number is: aaaa. Much like decimal: 0000.
The second number is: aaab. Decimal: 0001.
The third number is: aaac, decimal: 0002.
The fourth number is: aaad, decimal: 0003.

This process is known as incrementing, e.g. adding a constant value each time.

Now comes the tricky part, incrementing the last digit. According to number counting rules, when the last digit is reached, the last digit is replaced by the first and the digit in the next column is replaced. This is equivalent of a decimal number incrementing from 09 to 10.

So in the example above, the next number in the sequence is: aaba.

This is known as carry, as you are carrying the overflow to the next digit.

Converting Algorithm to Code
Looks like there is a loop to count from first digit to last digit:

#define MAXIMUM_DIGIT_POSITIONS 4
const char FIRST_CHAR = 'a';
const char LAST_CHAR = 'd';
std::vector<char> number(MAXIMUM_DIGIT_POSITIONS); // Reserve some slots.

void Print_Number(const std::vector<char>& number);

int main(void)
{
  // Initialize the number
  int position = 0;
  for (position = 0; position < MAXIMUM_DIGIT_POSITIONS; ++position)
  {
     number.push_back(FIRST_CHAR);
  }
  Print_Number(number);

  // Loop:  incrementing
  position = MAXIMUM_DIGIT_POSITIONS - 1; // Because arrays are zero based indexing
  while (number[position] < LAST_CHAR)
  {
    number[position] = number[position] + 1; // Increment to next digit, same position.
    Print_Number(number);
  }

  // Pause before closing
  std::cout << "Paused. Press ENTER to close.\n";
  std::cin.ignore(100000, '\n');

  return EXIT_SUCCESS;
}

void Print_Number(const std::vector<char>& number)
{
  for (std::vector<char>::const_iter iter = number.begin();
       iter != number.end();
       ++iter)
  {
    std::cout << *iter;
  }
  cout << "\n";
}

Handling Carry
The above program demonstrates counting in a single column. But how to handle the incrementing of the last digit?

Looks like we need to increment the digit in the previous position.
Looking ahead, the value in the previous column will be incremented, until it too, needs to be increment. Thus the carry will be propagate to the previous column. Looks like another loop:

  // Loop: number of positions
  int propagation_position = position - 1;
  while (propagation_position >= 0)
  {
      while (number[position] < LAST_CHAR)
      {
        number[position] = number[position] + 1; // Increment to next digit, same position.
        Print_Number(number);
      }

      // Propagate the carry.
      while (propagation_position >= 0)
      {
        if (number[propagation_position] != LAST_CHAR)
        {
          ++number[propagation_position];
          number[propagation_position + 1] = FIRST_CHAR;
          break;
        }
        --propagation_position;
      }

      position = 0;
  }

The above new fragment has an outer while loop and a second inner while loop. The outer while loop controls the digit position. The second inner while loop handles the carry.

The whole program is designed so that you can adjust the number of digit positions and the number of digits in the sequence.

Summary
The brute force method for printing all the combinations is like counting numbers. The same principles apply: when the last digit is incremented, it is replaced by the first digit and the digit of the next column is incremented. This is repeated until all positions have been counted.

Walk through the above code with debugger or pen and paper to find any defects and understand the algorithm.

After you understand the algorithm, search your favorite C++ reference for "c++ combination permutation algorithm".

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • You're expanation makes a lot of sense, and it did cross mi mind to actually try it that way but couldn't wrap my head around the problem enough like to be able to do it. – Debianita Apr 13 '14 at 19:48