Você está na página 1de 7

3.

7 Backtracking

• Método para realizar busca exaustiva, isto é, avaliar todas as


possíveis soluções de um problema;

• Geralmente aplicado a problemas de otimização;

• A idéia central é utilizar algum mecanismo (em geral, uma função de


corte) para avaliar se uma determinada escolha tem alguma chance
de levar a uma solução;

• Caso a escolha não possa levar a uma possível solução então todas
as opções que incluem aquela escolha podem ser ignoradas, isto é,
não precisam ser avaliadas;

3.7.1 – Passeio do cavalo

Dado um tabuleiro de xadrez com dimensões n × n, considere o cavalo


posicionado numa casa de coordenadas (x0, y0). Deseja-se obter, se existir,
uma seqüência de movimentos (seguindo as regras de movimento desta peça)
de modo que todas as posições do tabuleiro sejam visitadas exatamente uma
única vez.

Regras de movimento do cavalo:

Posições que o cavalo pode ocupar


a partir de uma dada posição
1
• Para solucionar este problema podemos utilizar o seguinte método:

(a) a partir da posição corrente, selecione uma posição possível (que ainda
não foi escolhida/avaliada)
(b) se a posição é aceitável, isto é, se ainda não foi visitada, registre-a
como “posição visitada”
(c) se ainda há posições a visitar tente um próximo movimento a partir da
posição escolhida no item (b)
(d) se a posição escolhida no item (b) não levou a uma solução, remarque a
posição como não visitada
(e) repita os passos acima até que uma solução seja obtida ou até que não
haja mais escolhas a partir da posição corrente

• Representação da informação para refinar a solução:

- tabuleiro: matriz de inteiros T de dimensional n × n, sendo que:


T [x,y] = 0 indica que a posição (x,y) ainda não foi visitada
T [x,y] = i indica que a posição (x,y) foi visitada no i-ésimo movimento;

- movimentos possíveis: o movimento do cavalo consiste em andar duas


casas numa direção e uma casa na outra direção, isto é, a partir da
posição (x,y) os 8 possíveis movimentos são dados por

(x+2, y+1) (x -2, y -1)


(x+1, y+2) (x -1, y -2)
(x -1, y+2) (x+1, y -2)
(x -2, y+1) (x+2, y -1)

Portanto, os possíveis movimentos podem ser obtidos representando-se


os deslocamentos nas direções x e y por um vetor com 8 posições sendo
que cada posição contém os deslocamentos dx e dy, isto é

k dx dy k dx dy
1 2 1 5 –2 –1
2 1 2 6 –1 –2
3 –1 2 7 1 –2
4 –2 1 8 2 –1

2
• Programa

/* +---------------------------------------------+
| Programa que determina o passeio do cavalo |
| num tabuleiro de xadrez de dimensões n x n |
| onde n é fornecido pelo usuário |
| Implementado por Marcus Vinícius A. Andrade |
| em 28/02/02 |
+---------------------------------------------+ */

#include <iostream.h>
#include <iomanip.h>

int n;
struct desloc { // deslocamentos nas direções x e y
int dx;
int dy;
};

// vetor de deslocamentos que define os possíveis


// movimentos do cavalo no tabuleiro de xadrez
desloc mov_cav[8]={{ 2, 1},{ 1, 2},{-1, 2},{-2, 1},
{-2,-1},{-1,-2},{ 1,-2},{ 2,-1}};

int **T; // tabuleiro


int nsq; // número de posiçoes no tabuleiro n^2

bool tente_mov(int i, int x, int y) {


int u,v; // posição do próximo movimento
bool q; // true => movimento com sucesso
int k;

k=0;
do {
q=false;
u = x+mov_cav[k].dx;
v = y+mov_cav[k].dy;
k=k+1;
3
// verifica se a posição é válida no tabuleiro
// e se a posição ainda não foi visitada
if (0 <= u && u < n && 0 <= v && v < n
&& T[u][v]==0) {
T[u][v]=i; // registra a visita
if (i < nsq) {
// ainda há posições no tabuleiro não visitadas

q = tente_mov(i+1,u,v);
if (!q) // movimento sem sucesso
T[u][v]=0; // remova o registo de "visita"
}
else q=true;
}
} while (!q && k<8);
return q;
}

void main()
{ bool ok;

cout << "Tamanho do tabuleiro = ";


cin >> n;
nsq = n*n;

// Aloca espaço para o tabuleiro


T=new (int* [n]);
for (int i=0; i < n; i++)
T[i]=new (int[n]);
for (int i=0; i < n; i++)
for (int j=0; j < n; j++)
T[i][j]=0;

4
T[0][0]=1;
ok=tente_mov(2,0,0);
if (ok) {
cout.setf(ios::right);
for (int i=0; i < n; i++) {
for (int j=0; j < n; j++)
cout << setw(4) << T[i][j] << " ";
cout << endl;
}
}
else
cout << "Nao ha solucao \n";
}

5
• Estrutura geral de um algoritmo usando Backtracking

inicialize a seleção de candidatos


repita
selecione o próximo candidato
se aceitável então
registre a escolha
se solução não está completa então
tente o próximo {corresponde à chamada recursiva}
se não obteve sucesso então
cancele o registro desta escolha
até obter sucesso ou não haver mais candidatos a escolher

3.7.2 Problema das 8 rainhas

Dado um tabuleiro de xadrez (com 8x8 casas), o objetivo é distribuir 8 rainhas


sobre este tabuleiro de modo que nenhuma delas fique em posição de ser
atacada por outra rainha.

Exemplo:

6
Observações:

• Há 88 = 16777216 possibilidades de configuração

• O número de configurações possíveis pode ser reduzido observando que


apenas uma rainha pode estar em cada linha. Logo, a solução pode ser
representada por um vetor Q (de inteiros) com 8 posições, sendo que

Q[i] = j indica que há uma rainha na posição (i,j) do tabuleiro

• Neste caso há “apenas” 8! = 40320 possibilidades de configuração

• Utilizando backtracking pode-se evitar o teste de diversas configurações


que não podem levar a uma solução

• Por exemplo, suponha que já foram colocadas k-1rainhas em posições


seguras nas primeiras k-1 linhas, então para colocar a k-ésima rainha é
necessário obter uma posição segura na linha k

• Pela modelagem adotada nunca haverá mais de uma rainha numa mesma
linha ou numa mesma coluna

• Resta apenas verificar as diagonais, o que pode ser feito adotando-se o


seguinte critério: duas rainhas nas posições (l1,c1) e (l2,c2) estão numa
mesma diagonal se e somente se
|l1 – l2| = |c1 – c2 |

• Para ilustrar este problema acesse os endereços

http://www.bhopalnet.com/eightq.htm
http://homepage.tinet.ie/~pdpals/8queens.htm

Você também pode gostar