Вы находитесь на странице: 1из 15

PRESENTACIÓN

Nombres:

Daniel Alejandro Idárraga Rico

Andrés Camilo Olaya Restrepo

Cristhian Camilo Galeano Rodríguez

Michael Ijají Soto

Búsqueda en profundidad (Árboles)

Maestro(a):

Nathalia María Henao Cardona

Institución Universitaria Antonio José Camacho

Facultad de ingeniería

Ingeniería de sistemas

Cali, Valle del cauca


PRESENTACIÓN

Nombres:

Daniel Alejandro Idárraga Rico

Cristhian Camilo Galeano Rodríguez

Andrés Camilo Olaya Restrepo

Michael Ijají Soto

Maestro:

Nathalia María Henao Cardona

Búsqueda en profundidad (Árboles)

Institución Universitaria Antonio José Camacho

Ingeniería de sistemas

2019
INTRODUCCIÓN

El proyecto está enfocado al tema de búsqueda en profundidad (a su vez en árboles) en el cual


mostraremos un problema y su aplicación para la solución del mismo, teniendo en cuenta su
definición y cómo se evalúa.
Los algoritmos de búsqueda existentes se aplican a árboles, muchos problemas de
optimización se pueden modelar para que se genere un árbol donde en sus nodos hay posibles
intermediarios para la solución del problema, cada uno de los algoritmos define el orden en el
cuál los nodos del árbol se generarán y la forma de encontrar la solución buscada
OBJETIVO GENERAL
Solucionar un problema presentado por este algoritmo, donde debemos hacer un recorrido de
todo el árbol de una manera correcta y ordenada.

OBJETIVOS ESPECÍFICOS
Hacer uso del backtracking para encontrar la mejor combinación de variables para solucionar
un problema
Analizar cómo funciona el backtraking en el problema planteado
Explicar cómo funciona el algoritmo y sus tipos de evaluación
¿QUÉ ES BÚSQUEDA EN PROFUNDIDAD?
Es un algoritmo de búsqueda no informada utilizado para recorrer todos los nodos de un grafo
(o árbol) de manera ordenada pero no uniforme. Se expande todos los nodos que se van
localizando en un camino correcto, cuando ya no queden más nodos por recorrer en ese camino
se regresa (Back tracking) de modo que repite el mismo proceso con cada uno de los hermanos
del nodo ya procesado.

EVALUACIÓN (CARACTERÍSTICAS)
Completitud: DFS es completo si y solo si usamos búsqueda basada en grafos en espacios de
estado finitos, pues todos los nodos serán expandidos, también existirá una solución dentro de
ese estado finito.

Optimalidad: DFS en ningún caso asegura la optimalidad, pues puede encontrar una solución
más profunda que otra en una rama que todavía no ha sido expandida.

Complejidad temporal: en el peor caso, es O (b ^M), siendo b el factor de ramificación


(número promedio de ramificaciones por nodo) y m la máxima profundidad del espacio de
estados.

Complejidad espacial: siendo b el factor de ramificación y d la profundidad de la solución


menos costosa, pues cada nodo generado permanece en memoria, almacenándose la mayor
cantidad de nodos en el nivel meta.
BACKTRACKING
es una estrategia para encontrar soluciones a problemas que satisfacen restricciones. El
término "backtrack" fue acuñado por primera vez por el matemático estadounidense D. H.
Lehmer en la década de 1950.

Los problemas que deben satisfacer un determinado tipo de restricciones son problemas
completos, donde el orden de los elementos de la solución no importa. Estos problemas consisten
en un conjunto (o lista) de variables a la que a cada una se le debe asignar un valor sujeto a las
restricciones del problema. La técnica va creando todas las posibles combinaciones de elementos
para obtener una solución. Su principal virtud es que en la mayoría de las implementaciones se
puede evitar combinaciones, estableciendo funciones de acotación (o poda) reduciendo el tiempo
de ejecución.

Esencialmente, la idea es encontrar la mejor combinación posible en un momento


determinado, por eso, se dice que este tipo de algoritmo es una búsqueda en profundidad.
Durante la búsqueda, si se encuentra una alternativa incorrecta, la búsqueda retrocede hasta el
paso anterior y toma la siguiente alternativa. Cuando se han terminado las posibilidades, se
vuelve a la elección anterior y se toma la siguiente opción (hijo [si nos referimos a un árbol]). Si
no hay más alternativas la búsqueda falla. De esta manera, se crea un árbol implícito, en el que
cada nodo es un estado de la solución (solución parcial en el caso de nodos interiores o solución
total en el caso de los nodos hoja).
Una búsqueda en profundidad empezando en el nodo A, con la suposición que las aristas a la
izquierda son escogidas antes de las aristas a la derecha, el algoritmo va a visitar los nodos en
esta orden: A, B, D, F, E, C, G. Se puede notar que, si el algoritmo no recuerde los nodos ya
visitados, el algoritmo podría continuar en una vuelta infinita A, B, D, F, E, A, B, D, F, E, etc.
sin visitar C o G.
Ejemplo domino
Tengamos un juego de dominós donde si hago caer uno domino, todos los demás dominós
que siguen a este caerán. Dado el número de dominós “n”, el estado del juego en la forma “x y” (
si domino “x” cae entonces domino “y” también caerá) , la cantidad de consultas a realizar, cada
consulta será el numero del domino el cual yo impulsaré. El problema me pide hallar cuantos
dominós caerán a partir del domino que yo impulsé.
Declaremos nuestras variables globales:

1 vector<int> ady[ MAX ]; //lista de adyacencia


2 int total; //la cantidad total de dominos que caerán
3 bool visitado[ MAX ]; //arreglo de domino caido
Modelemos el problema como un grado dirigido:

Ahora vemos cada consulta, la primera nos indica que impulsaré el domino numero 1, entonces al
hacer ello los dominos que caerán serán 1 -> 2 -> 5 ->3, debo retornar 4 la cantidad de dominos
caidos. Para la segunda consulta caéran solamente 4->3, y finalmente para 6 caerán 6->7->8

La solución lo relizaremos con un DFS como sigue:

1 void dfs( int u ){ //domino origen


2 total++; //aumento en mi respuesta la caida de un domino
visitado[ u ] = true; //domino "u" cayo
3 for( int v = 0 ; v < ady[ u ].size(); ++v ){ //verifico los demás posibles domino que caeran si
4 if( !visitado[ ady[ u ][ v ] ] ){ //si el domino adyacente no cayó entonces es el
5 evaluar
6 dfs( ady[ u ][ v ] ); //recursivamente veo que dominos caeran a partir
"u"
7 }
8 }
9 }
PROBLEMA
En un laberinto, se desea salir de la manera más factible que se pueda (haciendo referencia al
camino más corto posible). Recorriendo todos los nodos internos del árbol (que en este caso sería
el laberinto) evaluando los recorridos y determinar cuál de estos es la mejor opción para tener un
resultado más favorable para llegar al final (el resultado de todas las pruebas).
Teniendo en cuenta el código siguiente para la operación deseada.

def buscarDesde(laberinto, filaInicio, columnaInicio):

laberinto.actualizarPosicion(filaInicio, columnaInicio)

# Verificar casos base:

# 1. Hemos tropezado con un obstáculo, devolver False

if laberinto[filaInicio][columnaInicio] == OBSTACULO :

return False

# 2. Hemos encontrado un cuadrado que ya ha sido explorado

if laberinto[filaInicio][columnaInicio] == INTENTADO:

return False

# 3. Éxito, un borde exterior no ocupado por un obstáculo

if laberinto.esSalida(filaInicio,columnaInicio):

laberinto.actualizarPosicion(filaInicio, columnaInicio, \

PARTE_DEL_CAMINO)

return True

laberinto.actualizarPosicion(filaInicio, columnaInicio, INTENTADO)

# De lo contrario, use cortocircuitos lógicos para probar cada

# dirección a su vez (si fuera necesario)

encontrado = buscarDesde(laberinto, filaInicio-1, columnaInicio) or \

buscarDesde(laberinto, filaInicio+1, columnaInicio) or \

buscarDesde(laberinto, filaInicio, columnaInicio-1) or \


buscarDesde(laberinto, filaInicio, columnaInicio+1)

if encontrado:

laberinto.actualizarPosicion(filaInicio, columnaInicio, \

PARTE_DEL_CAMINO)

else:

laberinto.actualizarPosicion(filaInicio, columnaInicio, \

CAJELLON_SIN_SALIDA)

return encontrado

[ ['+','+','+','+',...,'+','+','+','+','+','+','+'],

['+',' ',' ',' ',...,' ',' ',' ','+',' ',' ',' '],

['+',' ','+',' ',...,'+','+',' ','+',' ','+','+'],

['+',' ','+',' ',...,' ',' ',' ','+',' ','+','+'],

['+','+','+',' ',...,'+','+',' ','+',' ',' ','+'],

['+',' ',' ',' ',...,'+','+',' ',' ',' ',' ','+'],

['+','+','+','+',...,'+','+','+','+','+',' ','+'],

['+',' ',' ',' ',...,'+','+',' ',' ','+',' ','+'],

['+',' ','+','+',...,' ',' ','+',' ',' ',' ','+'],

['+',' ',' ',' ',...,' ',' ','+',' ','+','+','+'],

['+','+','+','+',...,'+','+','+',' ','+','+','+']]

class Laberinto:

def __init__(self,nombreArchivoLaberinto):

filasEnLaberinto = 0

columnasEnLaberinto = 0

self.listaLaberinto = []

archivoLaberinto = open(nombreArchivoLaberinto,'r')

filasEnLaberinto = 0

for linea in archivoLaberinto:


listaFila = []

columna = 0

for caracter in linea[:-1]:

listaFila.append(caracter)

if caracter == 'S':

self.filaInicio = filasEnLaberinto

self.columnaInicio = columna

columna = columna + 1

filasEnLaberinto = filasEnLaberinto + 1

self.listaLaberinto.append(listaFila)

columnasEnLaberinto = len(listaFila)

self.filasEnLaberinto = filasEnLaberinto

self.columnasEnLaberinto = columnasEnLaberinto

self.xTranslate = -columnasEnLaberinto/2

self.yTranslate = filasEnLaberinto/2

self.t = Turtle(shape='turtle')

setup(width=600,height=600)

setworldcoordinates(-(columnasEnLaberinto-1)/2-.5,

-(filasEnLaberinto-1)/2-.5,

(columnasEnLaberinto-1)/2+.5,

(filasEnLaberinto-1)/2+.5)

def dibujarLaberinto(self):

for y in range(self.filasEnLaberinto):

for x in range(self.columnasEnLaberinto):

if self.listaLaberinto[y][x] == OBSTACULO:

self.dibujarCajaCentrada(x+self.xTranslate,
-y+self.yTranslate,

'tan')

self.t.color('black','blue')

def dibujarCajaCentrada(self,x,y,color):

tracer(0)

self.t.up()

self.t.goto(x-.5,y-.5)

self.t.color('black',color)

self.t.setheading(90)

self.t.down()

self.t.begin_fill()

for i in range(4):

self.t.forward(1)

self.t.right(90)

self.t.end_fill()

update()

tracer(1)

def moverTortuga(self,x,y):

self.t.up()

self.t.setheading(self.t.towards(x+self.xTranslate,

-y+self.yTranslate))

self.t.goto(x+self.xTranslate,-y+self.yTranslate)

def tirarMigaDePan(self,color):

self.t.dot(color)
def actualizarPosicion(self,fila,columna,val=None):

if val:

self.listaLaberinto[fila][columna] = val

self.moverTortuga(columna,fila)

if val == PARTE_DEL_CAMINO:

color = 'green'

elif val == OBSTACULO:

color = 'red'

elif val == INTENTADO:

color = 'black'

elif val == CAJELLON_SIN_SALIDA:

color = 'red'

else:

color = None

if color:

self.tirarMigaDePan(color)

def esSalida(self,fila,columna):

return (fila == 0 or

fila == self.filasEnLaberinto-1 or

columna == 0 or

columna == self.columnasEnLaberinto-1 )

def __getitem__(self,indice):

return self.listaLaberinto[indice]
JUSTIFICACIÓN
Buscamos darle solución a estos problemas con el uso de búsqueda en profundidad y back
tracking (éste último es muy importante ya que para poder hacerlo posible tenemos que hacer
una vuelta atrás para encontrar el camino factible que estamos buscando, en caso dado de que no
se pueda, el algoritmo fallará y no se dará solución al problema), buscando una solución a los
dos problemas planteados en donde la solución sea la más factible para solucionar el dilema que
nos plantea los ejercicios anteriores con los métodos anteriormente nombrados.
BIBLIOGRAFÍA
https://es.wikipedia.org/wiki/B%C3%BAsqueda_en_profundidad
https://prezi.com/txb6khxu50ps/algoritmo-de-busqueda-en-profundidad/

https://es.wikipedia.org/wiki/Vuelta_atr%C3%A1s

https://www.microsiervos.com/archivo/ordenadores/algoritmos-vuelta-atras-backtracking.html

http://programandoandojs.blogspot.com/2013/08/recorrido-en-anchura-y-en-profundidad.html

Вам также может понравиться