You are on page 1of 40

Algoritmia: Bsquedas y Recursividad

Pablo San Segundo (C-206)


pablo.sansegundo@upm.es

Ejemplo
Mapa de celdas

1 6 11 16 21

2 12 17 22

3 8 18 23

4 9 14 O

5 10 15 D

GRADO DEL GRAFO?

Escribir un algoritmo que permita establecer si existe un camino desde O (24) a D (20)

Algoritmo
1. 2. 3. 4. 5. N(O) := Vecinos de O Seleccin no determinista de un vrtice v de N(O) Si D est en N(O) FINSalida TRUE Repetir desde paso 1 para N(v) Salida FALSE

ASPECTOS DE IMPLEMENTACIN

Lista de NODOS_ABIERTOS Lista de NODOS_VISITADOS

Operaciones En el paso 1 se aaden a ABIERTOS los nuevos vecinos que no estn en VISITADOS ni en ABIERTOS En el paso 3 se extrae un elemento de ABIERTOS y se pasa a VISITADOS

Detalles: iteracin dinmica set<int>


set<int> s; set<int>::iterator it; it=s.begin(); int v; while(it!=m_open.end() ) { v=(*it);
//.

it++; }

set<int> s; set<int>::iterator it; set<int>::iterator it2; it=s.begin(); int v; int new_member=15; while(it!=m_open.end() ) { v=(*it);
//.

set<int> s; set<int>::iterator it; set<int>::iterator it2; it=s.begin(); int v; while(it!=m_open.end() ) { v=(*it);


//.

v.insert (new_member); //. (it2=it)++; v.erase(it); (it=it2); if(it==v.end()){ //.correccin it=v.begin(); } }

(it2=it)++; v.erase(it); (it=it2); }

Funciones para manipular set<int>


bool SetOfInt::IsEmpty (const set<int>& set) bool SetOfInt::IsMember(const set<int>& setA, int v) void SetOfInt::ClearSet (set<int>& set)
return set.empty(); return set.clear();

if (setA.find(candidate) != setA.end()) { return true; } else { return false; }

Programacin el ejemplo Path (I)


Inicio: aadir vecinos de O a ABIERTOS y O a VISITADOS m_closed.insert(m_o); for (int i=0; i<m_pg->GetSize(); i++){ if (m_pg->m_graph[m_o][i]) m_open.insert(i); } Si v_sel est en VISITADOS, borrar de ABIERTOS y elegir siguiente vrtice de ABIERTOS if(SetOfInt::IsMember(m_closed,v_sel)){ (it2=it)++; m_open.erase(it); it=it2; continue; } Comprobar si el vrtice elegido es solucin if (v_sel==m_d) break;

Programacin del ejemplo Path (II)


Aadir vecinos de vrtice elegido a ABIERTOS que no estn en CERRADOS for (int i=0; i<m_pg->GetSize(); i++){ if(m_pg->m_graph[v_sel][i] && ! SetOfInt::IsMember(m_closed,i) ) m_open.insert(i); }

Borrado del vrtice elegido de ABIERTOS (it2=it)++; m_open.erase(it); it=it2; if (it==m_open.end()){ it=m_open.begin(); }

Bsqueda primero en anchura (BFS)


Mapa de celdas

1 6 11 16 21

2 12 17 22
O
1 2 18 4 17 7 12 5 8 23

3 8 18 23

4 9 14 O

5 10 15 D

3 22 6 21 16 ABIERTOS

ABIERTOS es una cola (FIFO)

Bsqueda primero en profundidad (DFS)


Mapa de celdas

1 6 11 16 21

2 12 17 22
O
1 2 18 3 17 4 12 7 5 23

3 8 18 23

4 9 14 O

5 10 15 D

6 22 8 21 16 ABIERTOS

ABIERTOS es una pila (LIFO)

Primero en anchura vs. profundidad


Anchura

Profundidad

Garantiza encontrar la solucin La solucin (camino) es ptima Exponencial en recurso ESPACIO con la profundidad del rbol. No aplicable para espacios de bsqueda grandes

No garantiza encontrar la solucin La solucin (camino), si la encuentra, no tiene porqu ser ptima Lineal en recurso ESPACIO con la profundidad del rbol de bsqueda Aplicable para espacios de bsqueda grandes Se puede implementar mediante recursividad

Programacin BFS del ejemplo PathList (I)


Aadir vecinos de v_sel de ABIERTOS que no estn en CERRADOS for (int i=0; i<m_pg->GetSize(); i++){ if ( m_pg->m_graph[v_sel][i] && ! ListOfInt::IsMember(m_closed,i) && !ListOfInt::IsMember(m_open,i) ) { m_open.push_back (i); // almacenamiento del nodo padre (opcional) m_father_info[i]=v_sel; // map<key=hijo, padre> } }

Borrado de v_sel de ABIERTOS y decisin del siguiente elemento a expandir (it2=it)++; m_open.erase(it); it=it2;

// expansin FIFO

Programacin BFS del ejemplo PathList (II)


Reconstruccin de la solucin int v=m_d; map<int, int>::iterator it3; r.push_back(m_d); while (m_father_info[v] != m_o) { v=(m_father_info.find(v)second); r.push_back (v); } r.push_back (m_o);

Busqueda DFS (iterativa): PathList (II)


Aadir vecinos de v_sel de a ABIERTOS que no estn en CERRADOS for (int i=0; i<m_pg->GetSize(); i++){ if ( m_pg->m_graph[v_sel][i] && ! ListOfInt::IsMember(m_closed,i) && !ListOfInt::IsMember(m_open,i) ) { m_open.push_front (i); }
// almacenamiento del nodo padre (opcional)

m_father_info[i]=v_sel; }

Borrado de v_sel de ABIERTOS y decisin del siguiente elemento a expandir m_open.erase(it); it=m_open.begin();
// expansin LIFO

Recursividad
Paradigma de programacin tal que una funcin contiene una llamada a s misma
FACTORIAL (n) Salida IF(n==1) THEN return 1; ELSE return (n*FACTORIAL (n-1)); END-FACTORIAL Ejecucin contina por aqu

TRAZA EJECUCIN FACTORIAL(5) 24 120

6 3 4 4 5

2 2 3 4 5 Salida n=1

5 Pila del sistema

Trmino general de una sucesin


yk = yk 1 + yk 2 y0 = 0, y1 = 1

#define N 10 int Rec (int n) { if (n==0) return 0; if (n==1) return 1; return (Rec (n-1) + Rec (n-2)); } void main() { int vector [N]; vector [0]=0; vector [1]=1; for (int i=2; i<N; i++){ vector [i]=vector [i-1]+vector [i-2]; } } ARBOL DE RECURSIN BINARIO

1.15

Bsqueda DFS implementada recursiva


Inicio: Estado actual=nodo raz
DFS (Estado_Actual) Declarar espacio en memoria para almacn S If (Estado_actual = solucin) Then FIN S= estados vecinos (Estado_actual ) Salida If( S = ) then return For each Estado_Nuevo en S DFS (Estado_Nuevo) EndFor END-DFS BT 1 2 3 4 2 5 1 3 6 7

4 5 2 3

BT

BT

2 3

Papel de la pila del sistema? Cmo almacenar el camino?

6 7 2 3

Implementacin DFS recursiva


En cada nodo del rbol de bsqueda:


Seleccin del nuevo nodo a expandir v_sel a partir de ABIERTOS Condiciones de salida:

Nodo hoja? BACTRACK Es solucin FIN

Generacin de nuevos vecinos de v_sel ABIERTOS_NEW Expansin recursiva con ABIERTOS_NEW

EJEMPLO-I
yk = yk 1 + 2 yk 2 3 yk 3

Implementacin no recursiva?

y (0) = 0, y (1) = 1, y (2) = 2

PROGRAMA RECURSIVO: PRIMEROS N ELEMENTOS

int Rec (int n) { if (n==0) return 0; if (n==1) return 1; if (n==2) return 2; return (Rec (n-1) + 2*Rec (n-2) - 3*Rec(n-3)); }

ARBOL TERNARIO : nmero de nodos en funcin de N ?

EJEMPLO-II
yk = yk 1 + 2 yk 2 3 yk 3 y (0) = 0, y (1) = 1, y (2) = 2

PROGRAMA RECURSIVO: PRIMEROS N ELEMENTOS

int Rec (int n) { if (n==0) return 0; if (n==1) return 1; if (n==2) return 2; return (Rec (n-1) + 2*Rec (n-2) - 3*Rec(n-3)); }

ARBOL TERNARIO : nmero de nodos en funcin de N ?

EJEMPLO-III (Feb. 2009)


Se pretende romper la clave de entrada en un servidor remoto, compuesta de 6 dgitos del 0 al 9 ambos inclusive. Para ello se dispone de la aplicacin que permite bombardear a dicho servidor con todas las diferentes claves posibles y es necesario implementar exclusivamente el generador de claves. La estructura de datos a utilizar ser un vector clave de 6 posiciones. En cada posicin de clave se encuentra un dgito de la clave completa (clave[0] el primer dgito, clave[1] el segundo dgito etc.). Se pide: A) Implemente un algoritmo iterativo en C para generar todas las claves completando el cdigo que aparece a continuacin:

#define TAM_CLAVE #define TAM_NUMEROS

6 10 COMPLEJIDAD COMPUTACIONAL?

void main(){ int clave[TAM_CLAVE]; // }

SOLUCIN-A
for(int i=0; i<10; i++) for(int j=0; j<10; j++){ for(int k=0; k<10; k++){ // clave[0]=i; clave[1]=j; clave[2]=k; // } } }

VENTAJAS / INCONVENIENTES

EJEMPLO III (Feb. 2009)


B) Escriba un algoritmo recursivo de tipo primero en profundidad claves. Para ello complete el cdigo siguiente: #include <iostream.h> #define TAM_CLAVE #define TAM_NUMEROS int clave[TAM_CLAVE]; para generar todas las

6 10

void FuncRec(int depth){ if(depth == TAM_CLAVE){ //salida de recursin //.mostrar clave en pantalla return; } //generacin de sucesores y llamada recursiva clave[depth]=-1; for(int i=0; i<TAM_NUMEROS; i++){ clave[depth]+=1; FuncRec(depth+1); } } void main(){ FuncRec(0); }

VENTAJAS / INCONVENIENTES

EJEMPLO-PERMUTACIONES
permut (ARRAY Valor, POS_ESCRITURA k) NUM_DIGITOS N static num= -1; num = num+1; Valor[k] = num; IF (num == N) Mostrar (Valor); ELSE FOR (int i = 0; i < N; i++) IF (Valor[i] == 0) permut (Valor, i); ENDIF ENDFOR ENDIF num = num-1; Valor[k] = 0; END-permut

Salida (nodo hoja)

Sucesores

Backtrack

VALOR [N]

1-N

1-N

1-N

1-N

PERMUTACIONES 3 ELEMENTOS
VALOR =

0 0
num=1 K=1

0
num=1 K=0

0 2 0 2

0 3 0 3 0 3
BT BT

1 1

BT

0 2 1

0 3 0 3

0 3 0
num=3 K=1 num=2 K=2

num=2 K=1

num=2 Valor[1]=0

0 1 1 0 2 1 3 2 2 2

1
num=3 K=2

num=num-1=3 Valor[k]=0

3
HOJA

PERMUTACIONES 4 ELEMENTOS
TRAZA
#define N 4 void main() { int Valor[N]; for (int i = 0; i < N; i++){ Valor[i] = 0; } permut (Valor, 0); }

Valor Num Nivel 1234 1203 1243 1020 4 3 4 2 3 4 2 4 3 4 2 3 4 3

BT

x x

Valores iniciales
VALOR = NUM = 0

1320 0 0 1324 1023

IMPLEMENTACI COMPLETA (permut.)


void permut (int* valor, int k){ static int num=-1; num++; valor[k]=num; if(num==N){
//..mostrar en pantalla

}else { for(int i=0; i<N; i++){ if(valor[i]==0){ permut (valor, i); } } } num--; valor[k]=0; }
//main

int main(){ int valor[N]; for (int i=0; i<N; i++){ valor[i]=0; } permut (valor, 0); return 0; }

RESOLUCIN COMPUTACIONAL

Anlisis preliminar del problema


Caracterizacin del problema Formalizacin Estimacin inicial del coste computacional Anlisis de diferentes representaciones

Modelado

Heursticas dependientes del dominio Reduccin del coste computacional

Implementacin

Algoritmo de bsqueda

Completos: BFS, DFS, etc. Estocsticos: Genticos, Hill Climbing ,Tabu etc.

Estructuras de datos Lenguaje + Codificacin


C, Java, C++, C#, Ruby, Python etc. Recursin, iteracin

EJEMPLO: PROBLEMA DE LAS N-REINAS


EXISTE SOLUCIN ?

EXISTE SOLUCIN PARA N>3 y N=1

CARACTERIZACIN:VERIFICACIN SOLUCIN (I)


UN SOLO NDICE

13 14 15 16 9 5
C1 C 2 = N + 1

10 11 12 6 2 7 3 8 4
APLICACIN

C1 C 2 = N 1

y DOS NDICES

x2 x1 = y2 y1

C2

C1
(0,0) x Complejidad?

MODELADO RELACIONAL (I)


RELACIONES BINARIAS R ENTRE PAREJAS DE CASILLAS Dos casillas estn relacionadas si al colocar una reina en cada casilla no se atacan entre si

MODELADO RELACIONAL-GRAFO (II)


GRAFO G con tantos vrtices como casillas y tantas aristas entre vrtices como relaciones binarias R entre casillas

9 8

7 8 9 4 5 6 1 2 3

6 4 5

ISLA

G CONTIENE TODA LA INFORMACIN DEL PROBLEMA ?

CARACTERIZACIN DE UNA SOLUCIN EN EL GRAFO?

MODELADO RELACIONAL-GRAFO (III)


13 14 15 16 9 5
16 15 14 13 12

10 11 12 6 2 7 3 8 4

Es solucin si forma un N-clique en el grafo

2 3 9 8 6 7

11

10

4 5

ESTIMACION DE COMPLEJIDAD EN FUNCIN DE N?

MODELADO CON PERMUTACIONES

F4 F3 F2 F1 1 2 3 4
F1=2

SOLUCIN F2=4 F3=1 F4=3

RESTRICCIONES HORZONTALES Y VERTICALES

Q = {1, 2,, N }

LA SOLUCIN ES UNA DE LAS PERMUTACIONES DE N NUMEROS DONDE CADA NMERO INDICA LA COLUMNA EN LA FILA RELATIVA

IMPLEMENTACIN

GRAFO PERMUTACIONES

DISTRIBUCIN / PARALELIZACIN DE BSQUEDA


PARADIGMA: DESCOMPOSICIN + INTEGRACIN DESCOMPOSICIN DEPENDIENTE DEL DOMINIO A) Bsqueda de una contrasea numrica de K dgitos

0-1

K-1

1-2

B) Encontrar K-clique ?

8-9

DESCOMPOSICIN INDEPENDIENTE DEL DOMINIO DIVISIN BFS 1 2 4 DFS 5 6 3 7 DFS

ARQUITECTURA PARA N-REINAS DISTRIBUIDAS


PARADIGMA: DESCOMPOSICIN + INTEGRACIN Busq. DFS DESCOMPOSICIN

Busq. DFS Cliente REPARTO BFS Busq. DFS

N_sol1 INTEGRACIN Busq. DFS + N_SOL Cliente + N_sol4 + + N_sol3 N_sol2 Servidores

EJERCICIOS EXAMEN (Sep. 2010) (I)


Se necesita un algoritmo para determinar una ruta posible entre dos ciudades cualesquiera ORIGEN y DESTINO. Para ello un driver de Base de Datos dispone de tres funciones: int GenCiudadesVecinas (Ciudad ciudad, Ciudad* ciudades_vecinas); int BorrarCiudades (Ciudad* ciudades_a_borrar, const Ciudad* ciudades_ref ); bool IsCiudadDestino (const Ciudad ciudad ); GenCiudadesVecinas: Para una ciudad c devuelve el conjunto de ciudades vecinas de c y retorna por valor el nmero de ciudades que componen dicha lista. BorrarCiudades: borra de la lista de ciudades pasada como segundo parmetro, las ciudades que ya se encuentran en la lista pasada como primer parmetro. Asimismo retorna el nuevo tamao de lista. IsCiudadDestino: devuelve TRUE si la ciudad pasada como parmetro es la ciudad destino. Se pide implementar un algoritmo recursivo para obtener un camino entre dos ciudades. Dicho algoritmo se encapsula en una nueva funcin con el esqueleto siguiente:

void RecCamino (Ciudad* lC, int nlC, int d) { Ciudad* pC= new Ciudad [MAX_CIUDADES_NIVEL]; // for (int i=0; i<nlC; i++){ int nC =GenCiudadesVecinas (lC[i], pC ); // RecCamino (pC , nC, d+1); } delete [ ] pC; }

EJERCICIOS EXAMEN (Sep. 2010) (II)


Interpretacin de los valores de los 3 parmetros de la funcin recursiva RecCamino en la primera llamada.

(Nota: Se parte de una ciudad ORIGEN)

Complete RecCamino para que termine nada mas encontrar una ciudad destino
bool RecCamino (Ciudad* lC, int nlC, int d) { Ciudad* pC= new Ciudad [MAX_CIUDADES_NIVEL];
//bucle de generacin de vecinos

for (int i=0; i<nlC; i++){ if (IsCiudadDestino(lC[i])) {return true;} int nV =GenCiudadesVecinas (lC[i], pC ); if (RecCamino (pC , nV, d+1)==TRUE) { return TRUE;} } } delete [ ] pC; return false; }

EJERCICIOS EXAMEN (Sep. 2010) (III)


Modifique el cdigo anterior para que almacene el camino solucin y no pase nunca por la misma ciudad
bool RecCamino (Ciudad* lC, int nlC, int d) { Ciudad* pC= new Ciudad [MAX_CIUDADES_NIVEL];
//bucle de generacin de vecinos

for (int i=0; i<nlC; i++){ if (IsCiudadDestino (lC[i])) { //SOLUCIONm_path; return true; } int nV =GenCiudadesVecinas (lC[i], pC ); int nVDif= BorrarCiudades(pC, m_path); m_path.push (IC[i]); if (RecCamino (pC , nVDif, d+1)==TRUE) { return TRUE;} m_path.pop (IC[i]); } } delete [ ] pC; return false; } EL CAMINO ENCONTRADO SER PTIMO?

EJERCICIO EXAMEN (Junio 2009)


Implemntese un procedimiento recursivo para mostrar en pantalla un nmero entero positivo en formato binario. Un ejemplo de sesin en un shell (para un ejecutable denominado conversor) sera:
Entrada: conversor 32 Salida: 10000 Entrada: conversor 64 Salida: 100000

Nota: La manera ms simple de realizar la tarea es ir dividiendo por dos el dato. Cada digito del nmero binario buscado es el resto de esa divisin entera. (Por ejemplo 13 en binario: 13/2 = 6; 13%2=1 // 6/2=3; 6%2=0 // 3/2 =1; 3%2=1; // 1; La conversin es 0x1101. Ntese que hay que reconstruir los restos al revs).

void binario(int i){ if(i==1) cout<<"1"; else { binario(i/2); cout<<i%2; } }

//tras de la llamada recursiva