Intuitively it is possible to realize that the number of possible combinations is equal to 2 n - 1 where n is the number of elements of the vector, so if the vector has an element the number of combinations is 1, if it has 2, the number of combinations is 3 and so on.
If the number of combinations is equal to 2 n - 1 it is possible to represent it with the bits that make up a int
. For example, if the vector contains two numbers, each combination can be represented as follows:
[1][2] corresponds to 11, as both numbers appear.
[1] corresponds to 10, because only the first number appears.
[2] corresponds to 01, because only the second number appears.
So, let’s go to the implementation of the algorithm. In the code, I used the condition buffer_int % 2 == 0
to check whether the bit in position i
is equal to 1 or equal to 0. And I used the instruction buffer_int /= 2;
to move to the next bit. Check yourself:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
int main(){
int quantidade = 0;
int numeros[31];
/*31, pois (2^31 - 1) é o número máximo de combinações permitidade pelo programa.
Seria relativamente fácil aumentar o número de combinações máxima para 2^63 - 1,
mas como o algoritmo tem complexidade exponencial, valores dessa grandeza não
são úteis do ponto de vista prático.*/
char buffer_str[64];
//recebe os dados do usuario e cria o array
while(quantidade < 31){
printf("Entre um numero ou 'exit' para sair.\n");
scanf("%s", &buffer_str);
if(strcmp(buffer_str, "exit") == 0){
break;
}
numeros[quantidade] = atoi(buffer_str);
quantidade++;
}
int i;
int32_t combinacao = 1;
int buffer_int;
while(combinacao < (int32_t) pow(2, quantidade)){
buffer_int = combinacao;
for(i = 0; i < quantidade; i++){
//se o bit na posicao i é igual a 1 imprima o número
if(buffer_int % 2 == 1){
printf("%d ", numeros[i]);
}
//divide buffer_int por 2 para verificar o próximo bit
buffer_int /= 2;
}
puts("");
combinacao++;
}
}
EDIT: I liked the suggestions made in the comments and made the following changes to the code:
I added the empty set to the set of possible combinations;
pow()
, in fact, it is not safe to calculate an entire power, it has therefore been replaced;
replaces the while
by a for
, for agreeing that it was the most appropriate;
I used the function sprintf()
and the variables elemento_str
and conjunto_str
to decrease excessive I/O and improve performance;
And finally, I also fixed a bug that happened when the user entered the maximum number of elements (31). I won’t go into details, but the right thing to do would be to use the guy uint32_t
and not the kind int32_t
.
Below the excerpt of the changed code:
int i;
uint32_t num_comb = 1;
//num_comb == numero de combinações possíveis
for(int i = 0; i < quantidade; i++){num_comb *= 2;}
uint32_t combinacao;
uint32_t buffer_int;
char elemento_str[8];
//"[] é o primeiro conjunto a ser impresso (conjunto vazio)."
char conjunto_str[128] = "[]";
for(combinacao = 0; combinacao < num_comb; combinacao++){
buffer_int = combinacao;
for(i = 0; i < quantidade; i++){
//se o bit na posicao i é igual a 1 imprima o número
if(buffer_int % 2 == 1){
sprintf(elemento_str, "%d ", numeros[i]);
strcat(conjunto_str, elemento_str);
}
//divide buffer_int por 2 para verificar o próximo bit
buffer_int /= 2;
}
printf("%s\n", conjunto_str);
conjunto_str[0] = '\0';
}
What was tried? What was your difficulty? What did you not understand about the problem of taking the set of all subsets of another set?
– Jefferson Quesado
what I did was to do the part of reading the vector with n numbers that the user informs, my difficulty is in assembling the subsets for generic cases
– L. Linhares