1
INF01056
Aula 07/08
Backtracking
Baseado no livro Programming Challenges
Backtracking
Busca sistemática de todas as possíveis soluções
Garante que a solução será encontrada, ao enumerar todas as possibilidades
Garante eficiência, nunca testando uma solução mais de uma vez
Utiliza força bruta, ao fazer busca exaustiva
Pode ser otimizada, ao descartar enumerações parciais que não conduzem ao resultado desejado (prunning)
Backtracking – Rotina
Genérica
Solução é modelada como um vetor (a1, a2, ...., an) Cada elemento ai representa uma parte na solução
Uma jogada de uma sequência Uma parte de um caminho
Um subconjunto de elementos etc
A cada passo, tem-se uma solução parcial com k elementos (a1, a2, ...., ak)
Testa-se se a solução desejada foi encontrada
Senão, tenta-se extender a solução adicionando mais um elemento no vetor (a1, a2, ...., ak , ak+1)
4
Rotina Genérica
bool finished = FALSE; /* found all solutions yet? */
backtrack(int a[], int k, data input) {
int c[MAXCANDIDATES]; /* candidates for next position */
int ncandidates; /* next position candidate count */
int i; /* counter */ if (is_a_solution(a,k,input)) process_solution(a,k,input); else { k = k+1; construct_candidates(a,k,input,c,&ncandidates); for (i=0; i<ncandidates; i++) {
a[k] = c[i];
backtrack(a,k,input);
! ! ! if (finished) return;!/* terminate early */ }
} }
5
Backtracking – Rotina
Genérica
– is_a_solution(a, k, input):
testa se os primeiros
kelementos do array a
forma uma solução desejada
(input permite passar dados específicos para a rotina) – construct_candidates(a,k,input,c,&ncandidates):
preenche o array c com o conjunto completo de todos os possíveis candidatos para a posição
k
do array a,
dado o conteúdo das k-1 primeiras posições
– process_solution(a,k,input): esta rotina imprime, conta, ou realiza o processamento desejado uma vez que a solução foi encontrada
6
Exemplo 1:
construir todos os
subconjuntos a partir de n elementos
process_solution(int a[], int k) { ! int i;! ! ! ! /* counter */
! printf("{");
! for (i=1; i<=k; i++)
! ! if (a[i] == TRUE) printf(" %d",i); ! printf(" }\n");
}
is_a_solution(int a[], int k, int n) {
! return (k == n);
}
/*! What are possible elements of the next slot in the permutation? */
construct_candidates(int a[], int k, int n, int c[], int *ncandidates) { ! c[0] = TRUE;
! c[1] = FALSE;
! *ncandidates = 2; }
7
Exemplo 2:
enumerar todas as
permutações de n elementos
process_solution(int a[], int k) { ! int i;! ! ! ! /* counter */
! for (i=1; i<=k; i++) printf(" %d",a[i]); ! printf("\n");
}
is_a_solution(int a[], int k, int n) { return (k == n); }
/*! What are possible elements of the next slot in the permutation? */
construct_candidates(int a[], int k, int n, int c[], int *ncandidates) { ! int i;! ! ! ! /* counter */
! bool in_perm[NMAX];!! /* what is now in the permutation? */
! for (i=1; i<NMAX; i++) in_perm[i] = FALSE; ! for (i=0; i<k; i++) in_perm[ a[i] ] = TRUE; ! *ncandidates = 0;
! for (i=1; i<=n; i++)
! ! if (in_perm[i] == FALSE) { c[ *ncandidates] = i;
! ! ! *ncandidates = *ncandidates + 1; }
8
The 8 queens problem
The eight queens problem is a classical
puzzle of positioning eight queens on
an 8x8 chessboard such that no two
queens threaten each other.
Deseja-se contar o número de soluções
possíveis (e não listá-las)
9
The 8 queens problem
Como formar o array a?
Booleanos: a[i] é verdadeiro se uma rainha está na casa i
Necessita de 64 posições do array
Um total de 264 = 1,84 x 1019 vetores a serem testados
Inteiros: a[i] é o índice da casa onde está a rainha i
Necessita de 8 posições do array
Um total de 648 = 2,81 x 1014 vetores a serem testados
Gera cada solução 8! = 40320 vezes
Inteiros: a[i] é o índice da casa onde está a rainha i, sendo os índices gerados em ordem crescente
Necessita de 8 posições do array
Um total 4,426 x 109 vetores a serem testados (combinações
10
The 8 queens problem
Como formar o array a?
Cada linha só pode ter uma e exatamente uma rainha
Limitar a busca para a i-ésima rainha às 8 casas da i-ésima linha
Espaço de busca de 88 = 1,677 x 107
Mas cada coluna só pode ter uma e exatamente uma rainha também
Primeira linha: 8 candidatos; segunda linha: 7; terceira linha: 6, etc
a[i] contém o número da coluna da i-ésima linha ocupada por uma rainha
11
The 8 queens problem
process_solution(int a[], int k) { ! int i;! ! ! ! /* counter */
solution_count ++; }
is_a_solution(int a[], int k, int n) { return (k == n); }
/*! What are possible elements of the next slot in the 8-queens problem? */
construct_candidates(int a[], int k, int n, int c[], int *ncandidates) { ! int i,j;! ! ! /* counters */
! bool legal_move;! /* might the move be legal? */
! *ncandidates = 0;
! for (i=1; i<=n; i++) { ! ! legal_move = TRUE; ! ! for (j=1; j<k; j++) {
! ! ! if (abs((k)-j) == abs(i-a[j])) /* diagonal threat */
! ! ! ! legal_move = FALSE;
! ! ! if (i == a[j]) /* column threat */
! ! ! ! legal_move = FALSE; } ! ! if (legal_move == TRUE) { c[*ncandidates] = i; ! ! ! *ncandidates = *ncandidates + 1; } } }