O documento descreve o algoritmo de backtracking para gerar todos os subconjuntos possíveis de um conjunto. Ele usa uma função recursiva F que gera os subconjuntos incrementando um vetor de bool que indica a inclusão de cada elemento. A função faz podas (backtracking) quando não é possível encontrar mais soluções pelo caminho atual.
2. Backtracking
• De acordo com o Wikipédia:
• Backtracking é um tipo de algoritmo que representa um refinamento da busca
por força bruta, em que múltiplas soluções podem ser eliminadas sem serem
explicitamente examinadas.
2
3. Backtracking
• A recursividade pode ser usada para resolver problemas cuja solução
é do tipo tentar todas as alternativas possíveis.
• O backtracking executa podas quando não é possível encontrar uma
solução pelo caminho escolhido.
3
9. Backtracking
• Imagine um problema com as seguintes características:
• Você tem que fazer uma série de decisões...
• Você não tem informações suficientes para saber o que escolher...
• Cada decisão leva a um novo conjunto de escolhas...
• Alguma sequência de escolhas pode ser uma solução para o seu problema...
• Backtracking pode ser uma boa forma de experimentar várias sequências de
decisões até encontrar uma que funciona!
9
10. Backtracking
• A busca em profundidade (DFS) explora tanto quanto possível um
ramo antes de retroceder. É o que acontece no backtracking!
10
11. Gerando todos os subconjuntos
• Problema: gerando todos os subconjuntos
• Temos um conjunto S = {1 ... N}
• Objetivo: imprimir todos os subconjuntos a partir de N elementos.
• Para S = {1, 2} (N = 2) temos os subconjuntos: {1,2}, {1}, {2}, {}
• {1, 2} é o mesmo que {2, 1}
• O número de possíveis subconjuntos é 2^N
11
12. Gerando todos os subconjuntos
• Ideia: ou o elemento faz parte do subconjunto ou não faz parte.
• Pode-se construir um vetor de bool de tamanho N.
• Para S = {1, 2}, teríamos um vetor inicialmente com {0, 0}.
• Para S = {1, 2, 3}, teríamos um vetor inicialmente com {0, 0, 0}.
• Esse vetor irá nos ajudar a construir todos os subconjuntos.
• Se vet é o vetor de bool, vet[i] indica se o i-ésimo elemento está ou
não está no subconjunto.
12
13. Gerando todos os subconjuntos
• Uma variável K indicará qual elemento será colocado ou removido do
subconjunto.
• S(K) = (true, false)
• Seja F nossa função para gerar todos os subconjuntos, ela pode ser
definida como F(K, N).
• Inicialmente F é chamada da seguinte forma:
• F(1, N) // indexando a partir do 1
13
14. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
14
1 pertence a S
2 pertence a S
K
vet = [1, 0]
15. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
15
1 pertence a S
2 pertence a S
K == N, imprime {1, 2}
vet = [1, 0]
vet = [1, 1]
16. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
16
1 pertence a S
2 pertence a S
imprime {1, 2} Backtracking, o vet até então era [1, 1],
quando retrocede, fazemos vet[K] = 0,
se K = 2, teremos que vet = [1, 0]
17. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
17
1 pertence a S
2 pertence a S
imprime {1, 2}
vet = [1, 0]
K == N, imprime {1}
18. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
18
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
ramo processado
19. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
19
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
backtracking vet era [1, 0],
como K = 1, fazemos vet[K] = 0,
portanto, vet = [0, 0]
20. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
20
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
vet = [0, 0]
2 pertence a S
21. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
21
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
2 pertence a S
K == N, imprime {2}
vet = [0, 1]
22. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
22
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
2 pertence a S
imprime {2}
backtracking...
vet = [0, 0]
23. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
23
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
2 pertence a S
imprime {2}
K == N, imprime {}
vet = [0, 0]
24. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
24
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
2 pertence a S
imprime {2}
K == N, imprime {}
ramo processado
25. Gerando todos os subconjuntos
• Construindo a árvore para S = {1, 2}, N = 2
25
1 pertence a S
2 pertence a S
imprime {1, 2}
imprime {1}
2 pertence a S
imprime {2}
imprime {}
Todos os subconjuntos
foram gerados
26. Gerando todos os subconjuntos
• Construindo a função F (indexando a partir do 0)...
26