Sie sind auf Seite 1von 24

ANALISIS Y DISEO DE ALGORITMOS

Backtracking(BT)
Bsqueda con retroceso o Backtracking

Es una tcnica que consiste en recorrer sistemticamente todos


los posibles caminos. Cuando un camino no conduce a la
solucin, se retrocede al paso anterior para buscar otro camino.
Si existe solucin, es seguro que se encuentra. El problema
viene a ser el tiempo de proceso.
Es deseable que solo recorra los caminos que conduzcan a la
solucin y no todos. Es posible hacerlo cuando estando en un
punto nos damos cuenta que si seguimos avanzando no
encontraremos ninguna solucin.
Es un tcnica netamente recursiva, aunque puede
implementarse iterativamente.
El backtracking bsicamente es un recorrido hasta el fondo de
un rbol, aunque el rbol es implcito.

A este tipo de bsqueda se le conoce como Bsqueda


Primero en Profundidad DFS (Depth First Search)

Elemento buscado
CARACTERSTICAS DEL ARBOL

El algoritmo de Vuelta atrs hace un recorrido en profundidad


en un rbol.
El rbol se construye en memoria por eso se dice que es
implcito.
El recorrido en profundidad regresa sobre sus pasos (retrocede)
cada vez que encuentra un camino por el que no debe o no
puede continuar.
DIMENSIONES DEL RBOL

La Altura
Hay k posibles decisiones que debemos tomar para
llegar a una solucin.

La Anchura
Cada decisin debe tomarse de un conjunto de
alternativas distintas (dominio).
DIMENSIONES
Anchura: nmero de alternativas (candidatos)

Altura
(profundidad):
La cantidad de
decisiones que
debemos tomar

Cuando queramos aplicar backtracking debemos primero


imaginarnos como ser el rbol que vamos a recorrer!
Esquema general:
Dado que en todo algoritmo de backtracking hay que recorrer un rbol y en
cada paso se necesita encontrar todas las alternativas posibles y luego
recorrerlas una a una, es que podemos pensar en el esquema siguiente:

1. Si se llego a la mxima profundidad del rbol, entonces mostrar


solucin (caso base)
2. Sino entonces
2.1 Construir cada candidato
2.2 Para cada candidato aadirlo a la solucin y llamar
recursivamente a la funcin con el nivel siguiente de profundidad.

Lo que cambia en cada problema es:


1) La forma de generar cada candidato
2) Los tipos de datos
3) El nmero de parmetros de la funciones
4) Aadirle condiciones adicionales propias del problema
5) Aadirle condiciones adicionales para reducir el rbol (podar)
Seleccin de objetos
Se tienen n objetos, cada uno puede o no ser
seleccionado, Cules son todas las formas
posibles de tomarlos? De cuntas maneras los
podemos escoger?
Supongamos que tenemos 4 objetos
Primero hay que pensar como ser nuestro rbol:

En cada nivel podemos decidir si elegir o no el artculo.

La cantidad de decisiones que se deben tomar depende de la cantidad


de artculos.

Dicha cantidad de decisiones es la profundidad (altura) del rbol.

0 1
0 1 0 1
0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1

Por ejemplo, el camino 1011 significa que se tomaron el primer, tercer y cuarto
artculos y no se tomo el segundo.
# include <iostream>
using namespace std; Cdigo
# define MAX 20 void BT (int k, int n, bool decision[ ])
void BT(int, int, bool [ ]); {
void imprimir(int, bool[ ]); bool cand[MAX];
int construyeCandidatos(bool [ ]);
void main(void) if (k==n)
{ int i, n; imprimir(n, decision);
bool decision[MAX]; else {
cout<<"Nro de elementos:"; int ncand=construyeCandidatos(cand);
cin>>n; for(int i=0; i<ncand; i++) {
decision[k]= cand[i];
// marcamos objetos como no escogidos BT(k+1, n, decision);
for(i=0; i<n; i++) }
decision[i]=false; }
BT(0, n, decision); }
}
int construyeCandidatos(bool cand[]) {
void imprimir(int n, bool decision[ ]) { cand[0]=true;
for(int i=0; i<n; i++) cand[1]=false;
cout<<decision[i]<<" "; return 2;
cout<<endl; }
}
Clculo de la complejidad
Dado que en cada llamada recursiva se invoca 2 veces a la misma
funcin y como hay n invocaciones por cada llamada recursiva, su
complejidad es:
(2n)
Note que al tener una complejidad exponencial, el backtraking no es una
tcnica muy eficiente, pero su ventaja es que siempre encontrar la
solucin si es que existe y si tuviramos todo el tiempo del mundo.

En este caso el anlisis de complejidad nos permite darnos una idea de


que tan rpido podemos obtener la solucin, o si es factible encontrarla,
en caso de no serlo debemos echar mano de otras tcnicas.

Podemos elegir no recorrer todos los nodos del rbol si sabemos que no
nos llevar a la solucin buscada. Para esto usamos restricciones que
pueden ser dadas en el enunciado de manera explcita o implcita.

Existen tcnicas para podar el rbol de bsqueda, tales como poda


alfa beta, algoritmo A*, o algn otro tipo de heurstica.
Subconjuntos que suman valor objetivo

DADO UN CONJUNTO DE NMEROS ENTEROS


ENCONTRAR TODOS LOS SUBCONJUNTOS CUYA SUMA
SEA EXACTAMENTE UN VALOR OBJETIVO.

Por ejemplo, sea el conjunto {2, 3, 6, 1, 5}, y si pedimos los subconjuntos


que sumen 9, stos sern:
Pensemos en nuestro rbol si tenemos los elementos {2, 3, 6, 1, 5}
entonces tendr 5 niveles y en cada nivel debo decidir si tomar o no
el elemento.

0 1
2 2
0 0
1 1

3 3
0 1 3 0 1 3
0 1 0 1
6 6 6 6
0 1 0 1 6 6 0 1 0 1 6 6
0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1
0
1 0 0 1 0 1 1 1 1 10 1 0 1 0 0 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1 0 1 0 1 0 1
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
#include <iostream> void bt(int k)
using namespace std; { bool cand[LIM];
#define LIM 20
int suma(int); if (k==n) return; // condicin base
int buscaCandidatos(bool []); int ncand = buscaCandidatos(cand);
void bt(int); for(int i=0; i<ncand; i++)
void impSol(int); { seleccion[k] = cand[i];
int n; // nro de elementos int s=suma(k);
int objetivo; // suma objetivo
int x[LIM]; // elementos if( s==objetivo ) impSol(k);
bool seleccion[LIM]; // objetos elegidos else if( s<objetivo ) bt(k+1);
int main() }
{ int i; }
cout<<"Nro de elementos: "; cin>>n; int buscaCandidatos(bool cand[ ])
cout<<"Objetivo: "; cin>>objetivo;
// marco todos como no seleccionados { cand[0]=true;
for(i=0; i<n; i++) seleccion[i]=false; cand[1]=false;
cout<<"Ingrese elementos: "; return 2;
for(i=0; i<n; i++) cin>>x[i]; }
bt(0); int suma(int k)
}
void impSol(int k) { int sum=0;
{ for(int j=0; j<=k; j++) for(int j=0; j<=k; j++)
if( seleccion[j]==1 ) if( seleccion[j]==1) sum += x[j];
cout<<x[j]<<" "; return sum;
cout<<endl; }
}
Variaciones

Encuentre las variaciones de n elementos tomados de r en r.

Las variaciones son las distintas formas en que pueden tomarse r


elementos de un total de n.

Cuntas son? Cules son?

r n! abc bac cab dab


V = --------- abd bad cad dac
n (n-r) ! acb bca cba dba
acd bcd cbd dbc
adb bda cda dca
4!
adc bdc cdb dcb
------ = 4x3x2 = 24 formas distintas
(4-3)!
# include <iostream>
# define MAX 30 void bt(int k) {
using namespace std; char cand[MAX];
char x[MAX], rpta[MAX]; if(k==r) imp();
int n, r; else {
void imp( ) { int ncand=construyeCandidatos(k, cand);
for(int i=0; i<r; i++) for(int i=0; i<ncand; i++) {
cout<<rpta[i]; rpta[k]=cand[i];
cout<<endl; bt(k+1);
} }
int construyeCandidatos(int k, char cand[ ]) { }
int i, j, ncand=0; }
bool encontrado; int main() {
for(i=0; i<n; i++) { cout<<"Ingrese Elementos:";
encontrado=false; cin>>x;
for(j=0; j<k; j++) cout<<"n="; cin>>n;
if(x[i]==rpta[j]) cout<<"r="; cin>>r;
encontrado=true; cout<<endl<<"Las variaciones son:"<<endl;
if(!encontrado) { bt(0);
cand[ncand]=x[i]; }
ncand++;
}
}
return ncand;
}
EL PROBLEMA DE LAS N REINAS
En un tablero de ajedrez
coloque 8 reinas sin que
se maten.
8

1
Ejemplo:
Vectores para el Problema 4 reinas

R
R 2 0 3 1
R 0 1 2 3

R R
2 0 3 0
R 0 1 2 3

Como no puede haber mas de una reina en una misma columna, entonces
podemos restringir el nmero de candidatos desde un principio, usando un
vector donde cada posicin i, indica la columna en que se encuentra la
reina, y el valor indica la fila en que se encuentra la reina.
R

R R R R R
R
R
R

R R R R R
R
R R R R R
R

Ejemplo:
rbol para Problema 4 reinas

Existen 2 Soluciones
EL PROBLEMA DE LAS N REINAS

# include <iostream>
using namespace std;
#define MAXCANDIDATOS 100
#define NMAX 20 // mximo tamao del tablero
int nroSol,n; // cuenta soluciones
int solucion[NMAX];
void imprimeSolucion() {
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++)
if( i==solucion[j] )
cout<<'R'<<' ';
else
cout<<'-'<<' ';
cout<<endl;
}
cout<<endl;
nroSol ++;
}
EL PROBLEMA DE LAS N REINAS
int construyeCandidatos(int k, int candi[]) {
int ncandidatos = 0;
for (int i=0; i<n; i++) {
bool band = true;
for (int j=0; j<k; j++) {
// restriccion de diagonal y de fila
if ( abs(k-j) == abs(i-solucion[j]) || i == solucion[j] )
band = false; break;
}
if (band) { int main(){
candi[ncandidatos] = i; cout<<"Medida del tablero: ";
ncandidatos++; cin>>n;
} nroSol = 0;
} BT(0);
return ncandidatos; cout<<"Num. Soluciones="<< nroSol;
} return 0;
}

Agregar
TAREA: funcin BT()

Das könnte Ihnen auch gefallen