Вы находитесь на странице: 1из 49
PARTE I I I Estructuras de datos avanzadas Recursividad: algortmos recursivos 271 La estrategia a seguir para emular un procedimiento recursivo P es: 1. Definir una pila para cada variable local y cada argumento, y una pila para alma- cenar direcciones de retorno. 2. Ena sentencia n donde se haga la Hamada recursiva a P « (J) Meter en as respectivas pilas los valores actuals de las variables locales y argumentos; (2) Meter en la pila de direcciones la direccidn de la siguiente sentencia « Inicializar los argumentos con el valor actual de ellos y empezar la ejecucién desde el principio del procedimiento. 3. Vuelta de la ejecucién después de Ia llamada recursiva «Si la pila de direcciones esté vacia, devolver control al programa invocador. ‘* Sacar de las pilas los valores de la cima. Llevar la ejecucién a la sentencia extraida de la pila de direcciones. 9.4.1. El problema de las Torres de Hanoi resuelto sin recursividad El problema de las Torres de Hanoi, cuya solucién recursiva se ha descrito, se puede resolver de forma no recursiva siguiendo esta estrategia. Algoritmo no recursivo Torres de Hanoi Los argumentos conocidos son: Ademés la pila de direcciones: PilaDir Crear pilas: psiay, pilaa, pilas, Pilac, Pizapir Las etapas a considerar en la construccién del algoritmo Torres de Hanoi son: 1 Condicién para acabar. oi ts = 1 entonces joribir Palo A fin et Palo 272 Estructura de datos. 2. Llamada recursiva, a) Guardar en pilas: Meter tN, Pilaw) Pilaa) pila) Pilach Meter(, PilaDir) 5) Actualizar los argumentos: New-a Intercanbiar B,C cee 6) Volver a paso 1 3. Escribir varitia a variiia c. 4, Segunda llamada recursiva: 4) Guardar en pilas: Meter (N, Pi1aN) Meter (A, Pilaa) Meter (B, PilaB) Meter (c, Pilac) Meter (, PilaDir) b) Actualizar los argumentos: wen cee Intercanbiar A, BeA ©) Volver a paso 1 5. Este paso se corresponde con el retorno de las llamadas recursivas. 4a) Si Pila vacia entonces fin de algoritmo: volver a la rutina lamadora. 5) Sacar de la pila: 6 Sacar(A, Pilea) Sacar(B, Pilas) Sacar(C, Pilac) Sacar (Dir, Piladiz) ) Iral paso que esta guardado en Dix. Recursividad: algortmos recursos. 273 Codificacién no recursiva del problema de las Torres de Hanoi Para realizar Ia codificacion del algoritmo no recursivo de las Torres de Hanoi es ne- cesario una pila de enteros (Pi1aN) y tres pilas de elementos char (Pilea, Pila B, Pi 1aC). Para simular direcciones de retorno se utiliza otra pila de enteros en la que se guarda | o 2, segiin se simule la primera llamada o la segunda llamada recursiva, Los tipos de datos y las operaciones estan en las unidades de pilas. uses Pilachar, PLlaint procedure jianoiter |v: integer: A, 8, Cr charl: Pils, Pilac: Pilechar-PrrPila; Pilap! Pilaint.PerPila; Paso: integer; Tr char? begin Pilachar.perear(Pilaal iachar Perear(Pi125}7 lacharPerear (Pi1aC} Pélaint.Perear (PilaN) ; bélaintPorear (PilaD) ; Pilaint .Pmeter (1,Pi1aD! 7 while not Pilaint.pvacia{PilaD) de fei 21) then begin Mover_discolN.a,C): Pilaint.peacar (Paso, Pilad! A€ not Pilsint.evacia(Pilad) then begin Pilachar.Paacar(A, PilaA) pilachar -Peacar(B,Pilaa); Pilachar Peacar(C,Pilec) Pilaint .Peacar iN, Piatt) end end flee begin pilaint .psacar (Paso, PilaD} case Paco of ts begin pilachar meter (A, Pi Pilachar.pneter (3, Pi Pilachar.PneteriC, Pilaint,Pmeter tt, €i1aN) 7 Pilaintpneter(2/2ilaD); (Paso actual} Pélaint pmeter (1,2! Das Br Bae r end: 2: begin Hover_disco(t,A,C)+ [No e@ necesavio almacenar los argumentos A, B, C, N pues no se utsiizan) pilaine .rmet 2,PALaD) 274 Estructura de dates Esta solucidn resulta un tanto farragosa debido a la utilizacién de 5 pitas. Una sim- plificacién facil que puede hacerse es utilizar una tnica pila, en ésta se guarda el estado completo de los argumentos y la direccién de retorno. En la unidad PilaStat esté declarado el tipo elemento, un registro con los campos necesarios para guardar 2, 8, C, Wy Dir, y ademas las operaciones de manejo de pilas. Los tipos de datos en la unidad PilaStat: femento = record Na, Dit: integer sna PerPila -*reemp, itenp = recora Info: Elenentor Sate: PtrPila ends El procedimiento Hanoiter2: procedure Honoiter2(l: integer: A, Pila: perpila, tT: Flenencor procedure Estado(var begin with st do Be Elenente; A,8,C: chars N,Di integer) ena ends begin Perear(Pilal: Becado(?, 2,2 Pmever(?, Pala while not pvacia(Pila! ao wien = ao cart, Pita) Af ine ="1) then Mover_discoisd, Pa, Pe) alee Recursividad: algoritmos recursivos 275 Pueter(T,Pila); (Bstado actual) Estado (7, Pa, Pe, PE,NG=1, 1); Pneter (T,Pila); end; 2: begin Wover_disco(Nd, Pa, Po): Batado(T, Pb, Pa, Pc, Paeter (tT, pila): ena ena ena En el programa Tor rehanoi se muestran diversas soluciones de las Torres de Hanoi seguin el nimero de discos. Se aplica tanto la solucién recursiva como a las dos solucio- nes iterativas. La salida se dirige a la impresora. program Torrenanoi tees Pilaint, Pilacha: Naxnundiscos = 15; A,B.cr ch: Pilastat ,ert, printer procedure mover_disco (N: integer: A.C: Char) + begin ritein(Lst, ‘Mover disco ",N,* de “,A," a "/C) end? procedure mover_torre(N: integer begin few <1 then mover_diseo(N,A,c) ons begin over_torre(N-1,A,C-B); mover_disco(tt, a,c} end; procedure Hanolterl(: integer; A, B, Cichar! pila, Pilac: Pilachar.ptrPilar Pilap: Pilaint.PerPila; Paso: Integer: begin Slachar, Perear(Pilaa}: slacharPerear (Pila 276 Estructura de datos Pilaint .Perear(PilaN}: Pilaint.Perear(PilaD) 7 Pilaint.pmeter (3, eL1aD) 1 while not Pilaint Pvacia(PileD) ao Ae (= 1) then begin Mover_disco(N. A.C): Pilaint .Psacar (Paso, PilaD! : Af not Pilaint.Pvacia(Pilad) then begin Pilachar.Psacar(A, Pilaal Pilachar.Psacar(B,Pi1aB] 7 Pilachar.Psacar (C, Pita) + Pilaant.Peacar (N, PilaN}) ena end Glee begin Pllaine.Peacar (Pago, Pi1aD) + case Paco of i: begin Pilachar.pmeter (A, Fi1aA) Pilachar.pmeter(s,PilaB); Pilachar.Pmeter{C,PilaCh Pitaint. Pneter [N, eilaN) Pilaint.pmeter(2/Pilap); {Pago actual) Pileint. Pmeter 1, PilaD: Nas Ne ena; 2: begin Mover_disco(N,a,Cl: Pilaine.Pmeter (1, PilaD); wis weds end ena) ona ends procedure Wanciter?(N: integer; A, 5, C:char) Pilar perpiia; 1: Elemento! procedure Fstado(var St: Elemento; A,8,C: char; ND begin with ot do begin Pb Pe Ra 38. ena begin Perear {Pia}: integer! Recursividad: algoriomos recursivos 277 Estado (T,A,8,C,N, 1) Paeter(T, Pia); whlle not Pyacia(Pila) 4 with 7 do begin Psacer (7, Pile! ie (va ='1) then Mover_disco(tid, Pa, Fc) Case Dir of 1: begin Pater (T, Pilal: Pmeter (T, Pilla); fends 2: begin Yover_disco(nd ena end ena write( Numero de discos?) eadin (tt) watii nin (2, .waxnundiscos) over_torre|N,A,5,C) wriveln (tse va con ',N, ‘discos'): writeiniLst, ‘Solucién iteratival con ‘,8,* discos"); Hanoiterl (W,A,B.C)? writelniLst, ‘Solucién iterativa? con’, N,' discos"); Hanoiver2 (1,4,5,C) 9.5. ALGORITMOS DE VUELTA ATRAS (BACKTRACKING) Esta téenica algoritmica recurre a realizar una busqueda exhaustiva sistemitica de una posible solucién al problema planteado. El procedimiento general es descomponer el proceso de tanteo de una solucién en tareas parciales. Cada tarea parcial se expresa fre- cuentemente en forma recursiva. El proceso general de los algoritmos de «vuelta atrés» se contempla como un método de prueba o bisqueda, que gradualmente construye tareas basicas y las inspecciona para 278 Estructura de datos determinar si conducen a la solucién del problema. Si una tarea no conduce a la solu- cién, prueba con otra tarea basica, Es una prueba sistematiea hasta llegar a la solucién, 0 bien determinar que no hay solucién por haberse agotado todas las opciones que probar. Aplicamos esta técnica algoritmica al conocido problema de la vuelta del caballo que se describe a continuacidn. En un tablero de ajedrez de Nx N casillas. Un caballo sigue los movimientos de las reglas del ajedrez. El caballo se sitia en la casilla de coordenadas (,,¥,). El problema consiste en encontrar, si existe, un circuito que permita al caballo pasar exactamente una vez por cada una de las casillas del tablero. La tarea basica en que va a basarse el problema es la de que el caballo realice un nuevo movimiento, o bien decidir que ya no quedan movimientos posibles. E! algoritmo que exponemos a continuacién trata de llevar a efecto un nuevo movimiento del caballo con el objetivo de visitar una vez todas las casillas, Algoritmo Caballo: inieto Repetiz Seleccionar nuevo movimiento del caballo Bi (Zstd en tablero| y (io pasé ya) entonces ado tablera) entonces Letado tablero) © (No née posibles movimientos) En los algoritmos de vuelta atrés siempre hay nuevas tentativas en busca de solucién, nuevos ensayos. En el easo de que un ensayo no conduzca a alcanzar la solucién, se da marcha aris. Esto es, se borra la anotacién hecha al realizarse el ensayo y se vuelve a hacer otro, en el caso de que sea posible (en el caso de un caballo, éste puede realizar hasta ocho movimientos desde una posicién dada). Para deseribir con més precisién el algoritmo, definimos los tipos de datos para re- presentar el tablero y los movimientos. ablero = array(1..N, i..N) of integer; El tablero se representa mediante un array de enteros para guardar el nimero de movimiento en el que pasa el caballo, Una posicién del tablero contendra: Rocursivided: algoritmos recursivos 279 { Por la casilla (x,%) no pasé el caballo. TIX) i Por la casilla (%,¥) pas6 el caballo en el movimiento i Para la accién de seleccionar un nuevo movimiento, hay que tener en cuenta que dada una posicién el caballo puede realizar 8 posibles movimientos. En una matriz de dos dimensiones se guardan los 8 desplazamientos relativos para conseguir un siguiente salto, La figura nos muestra los desplazamientos: oo} 2 “4 “1 +s oy 6 7 La condicién de que el nuevo movimiento esté en el tablero y de que no hubiera pasado anteriormente: (ein (LST) and (Yin 12.081) and (UK, ¥) = 0: La condicién «no completado tablero» se representa con el niimero de movimiento i y el total de casillas: Para no penalizar en tiempo de ejecucién, las variables array son definidas globales. CODIFICACION DEL ALGORITMO VUELTA DEL CABALLO CON UN METODO RECURSIVO lof integer: 280 Estructura de datos procedure caballo(1: integer; x, Y: integer; var S: boolean); ix, ty: integer; K: integer; begin 5 t= false; K 220; (Inicializa el conjunte posible de movimientos? xe MILE: fy i= Yo HOZIR] Ae ine in (1..N}) an@ (ny in (2..N]) then Ae TUNx, Ny) + 0 then begin TINk, Ny) i= Ty (Anota movimiento} sete +N chen begin (se produce un nuevo ensayo} Gaballo(+l, tx, By, 8) Af not 3 then {No s¢ alcanza 1a solucién} TINx, Ny] = 0 (Borrado de la anotacién para probar con ‘otro movimiento} ona else (Tablero conpletado) sis crue ena until 5 or (k= 8) ena En las sentencias del bloque principal se inicializa las posiciones del tablero y tos desplazamientos relativos para obtener nuevas coordenadas. begin Bite L BIZ.) ait.2) 5 W(2,2) BIL] FMIzay BULL] Petz) BU1,5) (2,5) B16) 1 H(2.6) BULL) PHIZIT) BULL) Poza) fort: nao for J := 1 to N do 12,3) = 0; {1 caballo parte de la casilta (2,1)) m1 cabatlo(2,1,1,8)1 Af 5 thea for T := 1 to N Go begin foro := 1 ton do write(T(t,o1:4)7 weitein ena oles writeln(‘'No SB ALCANZA soLUCTON*) 4. CONTENIDO CAPITULO 9 Recursividad: algoritmos recursivos 1. Recursividad 2. Cuando no utilizar recursividad, 3. Algoritmos divide y vence. ‘4. Implementacién de procedimientos recursivos mediante pilas. 9.5. Algoritmos de vuelta atras. 9.6. Problema de la seleccién optima 8.7. Problema de los matrimonios estables. RESUMEN, EJERCICIOS. PROBLEMAS. Un procedimiento o funcién recursiva es aquella que se llama a si mis- ‘ma. Esta caracteristica permite a un procedimiento recursivo repetirse con valores diferentes de parametros. La recursién es una alterativa a la iteracién muy elegante en la resolucién de problemas, especialmen- te si éstos tienen naturaleza recursiva, Normalmente, una solucién recursiva es menos eficiente en térmi- nos de tiempo de computadora que una solucién iterativa debido al tiempo adicional de llamada a procedimientos. En muchos casos, la recursion permite especificar una solucién mis simple y natural para resolver un problema que en otro caso seria difi- cil. Por esta raz6n la recursién (recursividad) es una herramienta muy potente para la resolucién de problemas y la programacién, 9.1, RECURSIVIDAD Un objeto recursivo es aquel que forma parte de si mismo, Esta idea puede servir de ayuda para la definicién de conceptos matematicos. Asi, la definicién del conjunto 263 Recursividaa: algoritmos recursives 281 La caracteristica principal de los algoritmos de vuelta atrés es intentar realizar pasos que se acercan cada vez més a la solucién completa. Cada paso es anotado, bo- rrandose tal anotacién si se determina que no conduce a la solucién, esta accién consti- tuye una vuelta atras. Cuando se produce una «vuelta atrésh se ensaya con otro paso (otro movimiento). En definitiva, se prueba sistematicamente con todas las opciones posibles hasta encontrar una solucién, o bien agotar todas las posibilidades sin llegar a Ta solucién. El esquema general de este método: procedimiento Ensayarsolucion Enicto Inielalizar cuenta de opciones de seleccién onar nuevo paso hacia La solucién ei vilido entonces anotar el paso #1 no completada golucién entonces EnsayarSolueién = partir del nuevo paso no aicanza solucién completa entence: borrar anotacién fini fin Masta (Completada solucién] © (No més opciones) fin Este esquema puede tener variaciones. En cualquier caso siempre habré que adaptar- lo a la casuistica del problema a resolver. 9.5.1. Solucién del problema «Salto del caballo» con esquema iterativo Ampliamos el problema anterior para encontrar todas las rutas que debe seguir el caballo para completar el tablero pero utilizando pilas y asi transformar el esquema recursivo en srativo, En la unidad Pi 1asC tenemos todas las operaciones de manejo de pilas. En la pila se almacena el nimero de movimiento, nimero de salto y posicién. A continuacién cescribimos el cédigo de Ia unidad Pilasc. unte Pitac face ey Nurmow: intes x: Indice: Y, indice a 282 Estructura de datos, perPila =*rcemp, itemp © record Info: Tipoelen; PtrPila procedure Porearivar Pila: PrrPila) function Pvacia(Pila: PtrPila): boolean; procedure Preter(var Pila: PrrPila; X: Tipoelen) Procedure Pcina(Pila: PtrPila; var X: Tipoelem); procedure Poorrar(var Pila: etrPila}: procedure Peacarivar Pila: PerPila; var X: Tipoelen) implementation procedure Perearivar Pila: PtrPilal; begin Pala r= mil ena function Pvacia(Pila: PerPilal: boolean: begin Pvacia += (pila = nil) end procedure Preter(var Pila: PtrPila; x: Tipoclem): Ae PtePilar begin ewtAl RrInfo = Xr Rrisate i= Fila: Pila i= A ends procedure Poima(vila: ecrPila; var x: Tipoelem); begin Af mot pvacia(Pila) then Kis Pila*.Info ena procedure Phorrar (var Plla: PtrPila); Ar PerPila; begin Af not pvacia(pila) then begin Rix Pilar Pile := pila*.sgter dispose ta ena enay procedure Poacar(var Pilar PtrPila; var X: ipoelen; Ar peePilay begin Le not Pvacia(Pila} then Recursividad: algontmos recursivos 283 in = pala, x t= Pila*-tafo: Pala r= Pilar sete; aisposetA ena ena; begin ena Esta unidad la utilizamos para escribir el programa que iterativamente encuentra to- das Jas rutas que puede seguir el caballo para recubrir el tablero, program Cabaiter cet, Pilace type Tncrementos = array [i.-8] of integer Tebla = array [indice, indice] of integer cp: Perpila: ke Tipoelen; Xn, Xp, Ya, Yp: integer; {ccordenadas casillas} Fila, Colunaa: tndice; Bl: eet of Indie Inc: Increnentos: (Despl Tablero : Tabla Soluciones, Salto, NunNov: Lategers Recorrido, Colecado + boolea santos relatives) procedure anotar(var sw: Tipoclen; Nim, S: integer: Uv: tnaicel : begin with Ii 60 begin Saito := S; ere) vir ena ena procedure escribenila (cp + PtrPilal begin Lecp <> mil then begin Escribepila (Cp*.satel: with cp” do weite (infe.numnov:4, info.calto:2,info.x:2,'-",info.y); ena ena procedure iniciarteblero (var Tablero :Tablal! Fila, Columna : Indice 284 — Estructura de datos begin for Fila :+ 1 to N do for colunna := 1 to N ao ‘Tablero[Fila, columa] ena procedure Incre(var Incx, Incy: Incrementos); Begin {Desplazamientos relatives para desde una posicién dada dar un salto de caballo} Incx(1) +e 2) Inc¥(1) Inex(2) := 4; Incy(2) imex(3) 2-1) taev(3} inex(4) i= -2; mncy(a] Inck(S] t= -2) Incyi5] Imex(6) i= -1) Inc¥i6] Incx(7) #2 4} Taey(7} Iex(8) te 2) Tnc¥(8] ena procedure Eecribetablero(var Tablero Tabla): Fila, Columna: Indice: begin for Columna := N downto 1 40 ‘begin for Fila :- 1t0N do rite (Tablero[Pila, Columnal: writeln end ena begin ‘eleser; RL re (1m; Incre(Tnex, Iney): Iniciartabiero(Tablero} : lirite (*Introduzca casilla inieial: Nunmov i= 17 with R ao begin readin (%,¥)3 Nanmoy = 1p Tablero[X,¥) := Numnov; Salta := 8 ena Perear (cp): Pmeter (Cp, RI: Recorrido := false; Soluciones := 0; wale not Pyacia (cp) do begin Tf Recorrido then begin Peima(cp, 8): with x do Tablero(x.¥] := 0% Salto := R.Salto: Pborrar (cp) Recursividad: algortmos recursivos 285 ha desde 1a que no {tvuelta atras* hasta llegar a una cay fe agotaron todos los altos y asi poder encontrar otra solucion while salto - &) and not Fyacia(cp) ae begin with © do Teblere[x,¥] += 7 Nunmoy :~ ounov - 2 AE not Pvacisicp) then begin ena S€ not Pyaciaicp! then begin Teblero IR.K.8.¥) 2-0; [Deshece anterior para biisqueda de otra solucisn wunnov := R.Nummoy - 11 Phor rae (CP! Recorride := false then Polocado := false: Pelmaicp, Rl; (Pere dar un nuevo Xn = RX + Incx|salto] Yn i= RoY + Incy[Salto) Af Gin in RL) and (Yn in RL) then Colocade i= Tablero (xn, Ynl = watit Colocado oF (Salto = 8) $f Colecada then (Anota movimiento) begin vablerolkn, Yel = wunzov Paeter (cp. Rls Af Nunnov = 8 #8 then (ruta conpletada begin Soluciones := Soluclones + 1 mriveint SouueioN "234, Soluctones): colocarse Munovel 2 partir de Nunmov while not colocado and not Fvaciatcp) de 286 Estructura ae datos begin (Marcha atrac: eo sacado cl movimiento anterior para nueva "prueba' con otra salt) Peimaicp, RI: with © do Tablero[x,¥) 1-0: Salto := R-saltos{Es el dltimo Salta) Phorrar (cp) S€ not Pyacia (Co) then begin Peima(cp. 8); wien & a0 begin Np r= x vo ie ¥ ena while (Salto < 8) and not Colocado do begin Salto r= salto +1 Xp i= Xp + Inex[Seltol; Yo t= Yp + Iney[Saltol: Af (im in BL) and (va in Rl) then if Tablero [xn, Yn) = 0 then begin Colocade += true; Nun: Rewummoy + 1 Tablero[in, Ya] +-Nunmov: Anotar(R, Nummov, Salto, Xa, abr Pmeter(Cb, 8); ena ona end { fin de if not Pracia ) fend { fin de while not colocado ) 4 {fin ge Lf not Pvacia | (fin del mente wiritein ( ‘Soluciones encontradas = ', Soluciones! ena. A continuacién son expuestos problemas tipicos que son resueltos siguiendo la es- trategia de los algoritmos de vuelta atris. 9.5.2. Problema de las ocho reinas El juego de colocar ocho reinas en un tablero de ajedrez sin que se ataquen entre si es un ejemplo del uso de los métodos de bisqueda sistemitica y de los algoritmos de vuelta ats. El problema se plantea de la forma siguiente: dado un tablero de ajedrez (8 * 8 casi- lias), hay que situar ocho reinas de forma que ninguna reina pueda atacar («comer») a cualquiera de las otras. En primer lugar recordamos la regla del ajedrez respecto de los movimientos de la reina, Esta puede moverse a lo largo de la columna, fila y diagonales donde se encuentra, Una primera conclusion es que cada columna puede contener una y s6lo una reina, por lo que la colocacién de la reina i queda restringida alas casillas de la Recursividad: algoritmos recursivos 287 ‘columna i, Por esta coincidencia el parametro i nos sirve de indice de columna dentro de la cual podremos colocarla en los ocho posibles valores de fila. En cuanto a los tipos de datos para representar las reinas en el tablero, como lo que nos interesa es determinar en qué fila se sitia la reina que esta en la columna i, defini- ‘mos un vector entero, El contenido de una posicién del vector serd 0, 0 bien el indice de fila donde se sitia la reina. type ila = array(t de reinae } En orden a buscar la solucién completa, la tarea basiea que exhaustivamente se prue- ba es colocar la reina i en las 8 posibles filas. La comprobacién de que dicho ensayo es valido tiene que hacerse investigando que en dicha fila y en las dos diagonales no haya otra reina colocada anteriormente. En cada paso se amplia el niimero de reinas coloca- das, hasta llegar a la solucién completa, o bien determinar que en un paso no sea posible colocar la reina. Entonces, en el retroceso se coloca la reina anterior en otra fila valida para realizar un nuevo tanteo. CODIFICACION Pilas = areay[i..N] of integer procedure colo: integer; var $+ boolean): function Valido(J: integer): boolean: {inspeceiona si la reina de 1a colusna J es atacada por alguna reing colocada anteriormente) vi boolean; begin for R:= 1 te J-1 do begin =v and (Roinas(R] <> Reinas(t) {xo esté en la misma fila ine eeté en alguna de las des diagonales:) (Reinas[] + J) <> (Reinas{xl + RNs UReinas ia] - 3) <> (Reinas(R] ~ Ri 288 Estructura de datos, ends begin K tz 0; {inicializar posibles movimieatos) repeat Reinas(T] :=X: (Tentativa de colocar reina 1 en tila K, a la vez queda anotade movisionte then @ then {f puede sustitvirse por m) {No completado ar_Reinas(I + 1, 8) Af not © then | Yuelha airds) {as @ veinas colocadas untét Sor (k 8) ena Observar que en la vuelta atrés se puede omitir borrar la anolacién ya que en | siguiente iteracién se prueba con otra fila, asignando un nuevo valor a la misma posicién del vector Reinas, En el blogue principal es escrita la solucién, write (Keinas (1:51 ena. 9.5.3. Solucién no recursiva al problema de las ocho reinas Al igual que la sotucién iterativa del salto del caballo, presentamos la solucién iterativa de las 8 reinas con una pila para emular las Hamadas recursivas, Ahora lo relevante en cada movimiento es el nimero de fila y de columna, ello es lo que guardamos en la pila A continuacién eseribimos el interface de la unidad Pi uate PLiaky interface type Rango = 2..N; Preeila = “Woda; sote: PerPila procedure Porearivar Pila: PrrPila| function PvaciaiPile: PtrPila}: boolean procedure procedure procedure (rin de la seceién de interface) Recursividad: algortmos recursivos 289 pueter|var Pila: PerPila: Nr, Col: word); Peima(Pila: PtrPila; var Ne, Col: word): Pborrar (var Pila: PerPila); Peacar (var Pila: PerPila: var Nr, Col: word); La codificacién del programa que encuentra una solueién al problema. program Reinaa_ity (situa N reinas sin atacarse en tablero N*N ba una sola eolucién) uses Crt, Pilar: type Pipocol = array (Rango) of boolean: Diagonalochatzda - array (2..2 * N) of boolean: (ila(nimero de reina) + Columna = cte.} Diagonalizdadcna = array (1 -N..N - 1] of boolean: (Fila e mimero de reins ~ colunna = cte.) Col, NE, Ne, i: integer: Golibre: Tipocol: (ilo hay reina en fila j-ésima) Dach: Diagonalachatzda; (no hay reina en Diagonal Dcha-Izdai Dizq: Diagonalzzdadcha; (no hay reina en Diagonal T2da-Dcha) cp: Pepila: Colocado: boolean: procedure Listarpilaicp: Ptrpile) begin while Cp*.sgte <> mil do begin weitelcp* Nr,” cp ends weiteln ena; procedure begin cel ico) Bach (tr DizgiNr ends procedure begin Col ical Déch [we Dizale ends begin eirser write|‘Tntroduzca dinensién del tablero: cpr.cod. 32 cps sate Liberar{var Col: Tipocol: var Ddch: DiagonalDchatzda: ‘Yar Diza: Biagonallzdabeha; Nr, Co: word); + col #= * co} ocupar(var Col: Tipocol: var Déch: DiagonalDchatzda; ‘var Dizq: Diagonaltzdapcha: Wr, Co: word): false: + col S col + false: false 290 Estructura de datos readin int) for i :-1 to NE do Colibre(i} :- true: for | :-2 to 2*Nf do Dach{il ues for i i= 1 NE to NE - 1 do Dizgii] sx true: Porear (Cp): Nr col i= 0 Peter (cp, Nr. Col) white(tir © Hf) ana not Pvacia(cp) de begin Ne i= r+ 1; Colocado <= fal: While not Colocade and [Col ~ NE) do begin Col := col + 1; Af colibre(cot} then Af odehttlr + Col) then tf DizgiNr - Col) then begin Scupar(colibre .o¢en, Pneter (cp, Nr, Coll: col t= 0 ena za, Mr, Col); ends Lf aot Colocado then begin LE cps <> 0 then begin Liberar(Colibre, Ddch, Dizg, cp*.te, Cp*.Col eercsena ol t= Cp*.Col ona, Phorrar (cp) Le evaciolcp! then writeln. (xo eNeuEs PRO SOLUCTON") ou Listarpila(cp) end. 9.5.4. Problema de la mochila Un esforzado corteo desea llevar en su mochila exactamente v kilogramos, se tiene para elegir un conjunto de objetos de pesos conocidos. Se desea cargar la mochila con un peso que sea igual al objetivo. El plantcamiento del problema de la mochila: dado un conjunto de pesos p1, p2, 3, « . Dn (enteros positivos), estudiar si existe una seleccién de pesos que totalice exac- tamente un valor dado como objetivo V. Por ejemplo, si V=12 y los pesos son 4, 3, 6, 2. 1, se pueden elegir el primero, el tercero y el cuarto, yaque 4+ 6 + 2 = 12. La representacion de los pesos se hace con un vector de nlimeros enteros. 264 Estructura de datos de los nimeros naturales es aquel conjunto en el que se cumplen las siguientes ca- racteristicas © O.es un niimero natural. © Elssiguiente mimero de un niimero natural es otro nimero natural Mediante una definicién finita hemos representado un conjunto infinito. El concepto de la recursividad es muy importante en programacién. La recursividad es una herramienta muy eficaz para resolver diversos tipos de problemas; existen mu- chos algoritmos que se describirén mejor en términos recursivos. Suponga que dispone de una rutina Q que contiene una sentencia de Hamada a si misma, 0 bien una sentencia de Hamada a una segunda rutina que a su vez tiene una sentencia de llamada a Ja rutina original Q. Entonces se dice que Q es una rutina re- Un procedimiento o funcién recursivos han de cumplir dos propiedades generales para no dar Ingar a un bucle infinito con las sucesivas lamadas: © Cumplir una cierta condicién o criterio base del que dependa la llamada re- ccursiva © Cada vez que el procedimiento o funcién se llamen a si mismos, directa o indirec- tamente, debe estar mas cerca del incumplimiento de la condicién de que depen- de la llamada. EJEMPLO 9.1. Secuencia de ntimeros de Fibonacci Esta serie numérica es un ejemplo tipico de cumplimiento de las dos propiedades ge- nerales de todo procedimiento recursivo. La serie de Fibonacci es: 0,1, 1,2, 3, 5,8, 13, 21, 34.0 El término inicial es ay = 0, y los siguientes son: a, = 1, a= 2, ay =3, a.=5, ds observandose que cada término es la suma de los dos términos precedente excepto ao y ay. La serie puede ser definida recursivamente del modo siguiente: Pibonacei(n) =n sin=0on=1 Fibonacci(n) = Pibonacei(n-2) + Fibonacci(n-1) para n>1 Esta definicién recursiva hace referencia a ella misma dos veces. Y la condicién para que dejen de hacerse llamadas recursivas es que n sea 0.0 J. La llamada recursiva se hace en términos menores de 7, 2-2, n-1, por lo que se va acercando a los valores de los que depende la condicién de terminacién, 9.2. CUANDO NO UTILIZAR RECURSIVIDAD La solucién recursiva de ciertos problemas simplifica mucho la estructura de los progra- mas. Como contrapartida, en la mayoria de los lenguajes de programacién las lamadas recursivas a procedimientos o funciones tienen un coste de tiempo mucho mayor que sus Recursividad: algortmos recursives 291 | maximo de pesos previsto } = array(1..n) of integer: El algoritmo para solucionar el problema tiene como tarea bésica afiadir un peso nuevo, probar si con ese peso se alcanza la solucién, 0 se avanza hacia la solucién. Es ‘una bissqueda sistemitica de la solucién hacia adelante. Si llegamos a una situacién de «cimpassen, en la que no se consigue el objetivo por que siempre es superado, entonces se retrocede para eliminar el peso afiadido y probar con otro peso para inspeccionar si a partit de &l se consigue el objetivo. Esto es, realizar otra biisqueda sistematica. La bolsa donde se meten los pesos viene representada por un tipo conjunto. Al afa~ dir un peso, la anotacién se realiza acumulando el peso y metiendo en la bolsa, el con- junto, el indice del peso. Para borrar la anotacién se opera a la inversa, CODIFICACION _ + {maximo de pesos previ: array[1..N) of integer Bolsa: set of 1..N; Wi integer? (Obseesvo} v el obi iCandidaco ce del peso # afadir icuenta Suma parcial de pesos procedure Hochila(v: integer; Candidato: integer begin —— te cue v then ete if (Cuenta < V) and (Candidate <= N) then begin Tes anotado 2 objeto Candidate y sigue 1a busqueda’ Bolsa := Bolsa + (Cendidatol : Mochila(v, Candidato + 1, Cuenta + Pesos{candidato), 5: if not 5 then (Zo excluide Candidato, para seguir tanteando con siguiente begin Bolea := Bolsa - [Candidato}+ Mochila(v, Candidazo + 1, Cuenta, 8) ena ena 292 Estructura de datos La llamada a Noch ila desde el bloque principal transmite el objetivo V, el candi- dato 1 y la suma de pesos 0. la(v, 1, 0, Soluctond; Eliminacién de la recursién en el problema de la mochila Para eliminar la recursividad introducimos una pila de enteros para almacenar el candi- dato actual y en otra pila de nimeros reales almacenar la suma parcial de pesos. Las llamadas recursivas a Mochila se producen en dos puntos, por lo cual el proble- rma de guardar la direccién de retorno Io solventamos con otra pila de enteros, en la que almacenamos tres posibles valores: 0. Indica que la llamada a Mochila procede de fuera del procedimiento. 1. Indica que es una Hamada recursiva a Mochila, en la cual se incluye Pesos [Candidato} dentro de la solucién 2. Indica que es la llamada recursiva a Mochila, consecuencia de Ia vuelta atrés al no alcanzarse la solucién completa. Pata realizar el procedimiento no recursivo de Mochila hay que incorporar la unidad Pilas para niimeros enteros y para niimeros reales. procedure ochila (Vi integer; Candidaco integer; var S: boolean) Peand Pilint: begin Perear (Peandi} ; Porear (peta) Pneter(0, Pstat); (Bs asignado el estado inicial) 4€ Cuenta = y then 4€ (Cuenta < V) and (Candidato <2 N) then @ anotado el objeto Candidate y sigue la Bolsa := Bolsa + (Candidato) Pesos [Candidacy Candidate” + 1; ele if (cuenta > vj and (Cimalpstat) = 0) oF (Candidate > N) then ecursividad: algoritmos recursivos 283 begin Phorrar (Psta ndidata = 1 Slee sf cima = 1 then Begin (So oxcluye al candidat y se vuelve a prob; Bolsa :- Bolsa - (Candidazol Pilareal.Peacar(Cuenta, Pouent): Candia: Candidate «1 Phorrar (stat): else Sf Cima(Perat) = 2 then begin al Jaz cualifican unidad Pal 9.5.5. PROBLEMA DEL LABERINTO Se desea simular el juego del laberinto. En el laberinto hay muros por los que no se puede pasar. El viajero debe moverse desde una posicién inicial hasta la salida del labe- rinto. El laberinto esta representado por una matriz de N * N, los muros son representa- dos en la matriz. por celdas que contienen el caracter 0, los caminos por celdas con el cardcter 1. La salida del laberinto viene indicada por la celda que contiene una S, La entrada al laberinto es jinica, sus coordenadas son conocidas. La representacién de datos es nto} of char, ALGORITMO El viajero parte de una casilla inicial, Desde una casilla puede moverse a cuatro posibles casillas (hacia el Norte, el Oeste, el Sur o el Este). El movimiento estar permitido sien la nueva casilla no hay un «muro», Cada vez que se pasa por una casilla se marca con tun '*" para asi saber el camino seguido hasta Ia salida. Si llegamos a una situacién de impasse», es decir estamos en una casilla desde la cual ya no podemos avanzar: se desanota la casilla, se marca la casilla como si fuera un muro para no volver a pasar por 294 Estructura de datos ella, se vuelve al anterior movimiento y se ensaya con un movimiento en otra direccion. El algoritmo termina cuando se alcanza la casilla de salida. CODIFICACION program Juego_laberinto; uses crt; const Neer Norte = 1; Sur = Oeste Este = type Latitud = Norte. .Sur; Longitud Oeste..Este; Laberinto = array(Latitud, Longitud] of char; var L: Laberinto; Exito: boolean; AO, Af: Latitud; LO, Lf: Longitud; procedure Entrada(var L: Laberinto); var Lat: Latitud; Lon: Longitud K, Km: integer; begin Clrscr; writeln ('Simulacién de laberinto de ',N ,'x', N); for Lat := Norte to Sur do for Lon := Oeste to Este do L{Lat, Lon] := '1'; repeat write('Nimero de "muros" (8..20): '); readin(K); ine nleekee eines Olle Km := 0; randomize; while Km < K do begin Lat 1 + random(Sur); Lon 1 + random(Este); if L{Lat, Lon]= '1' then begin L[Lat, Lon] := i Km := Km + 1 end end end; procedure VerLab(var L: Laberinto); Recursividad: algoritmos recursivos 295 for Lat := Norte to begin for Lon := Oeste to Este do write(L , Lon] Vi writelr end end; procedure Soluc ean); begin if Lt then {Her J := true else begin anza probando Este] then { ']' then J+ 1 OO: ta) i Norte..Sur] then {Al Sur} ce eee nen) Soluclaber(A+1, H, Q) end; if not © then begin L[A+1, if Al Oeste if L[ Soluc end; if not 0 then begin L{A,H-1] := '0'; if (A-1) i {Al Norte} Jf LA: Solu end; if not © then Te (eee ee end end; begin Entrada(L); VerLab(L); wri (' da readla ( L[A0,LO write('C readtir 296 Estructura de datos Aut] i= *8 Brito = false, Af Exito chen Morrer no salimos del laberinto!!') 9.5.6. Generacién de las permutaciones de n elementos La resolucién esta basada en la ley de formacién de las permutaciones de 1 elementos. Partiendo de las Permutaciones de 0 elementos se obtienen las Petmutaciones monarias tomando 1(k) elemento y situindolo en todas las posiciones posibles: p = 1. Las Permu- taciones binarias se obtienen tomando el 2(k) elemento y situandolo en todas las posi- ciones posibles: p = 2, p = 1. En definitiva, en el paso i el elemento i debe colocarse en las p= i, p= i 1, p= i-2, ., p= |. Para ello el array A esta indexado de 0 a n, guardando en la posicién p el ordinal de la permutacién (k) y en la posicién k, ordinal de Ia anterior permmutacion. El primer valor de p = 0. Cuando se aleanza k =n es escrito el contenido de la permutacién y después el «elemento» k es colocado en Alp] para asi ‘«colocar» el elemento k en posicién anterior. La solucién se plantea recursivamente, aplicando una variacién a la estrategia de backtracking para asi agotar todas las «solu- cciones» que ahora se convierten en grupos de 7 elementos. CODIFICACION Maxorado = 10 Br array [0..Naxgrado) of char = TA BC DE, FY, 8H type Rpuntager = 0..Maxgrado: A: areay [Apuntador} of Ap Xi char procedure 5) azApuntadors ‘esopermutacion; begin while Aa] <> 0 ao begin ite (alata) @ :=Algl: ena; procedure permuta(K,N:Apuntador) + Recursividad: algoriimos recursivos 297 ruta (Ke1,N) Ahora se "coloca* en la anterior, representado por AKI} Alp) t=A0#1: bot Alp; until p = 0; ena; begin until nin (1. -Maxerado writelnl'Permutaciones de *:50,N, ‘elenentos ALD) t= ari‘) ;readin (i); 9.6. PROBLEMA DE LA SELECCION OPTIMA En los problemas del Salto de caballo, Ocho reinas y Mochila se ha aplicado la estrate- aia de vuelta atrés para encontrar una tinica solucién. Con la misma base, se ha hecho una ampliacién para encontrar asi todas las soluciones. Ahora no se trata de encontrar una situacidn fija 0 un valor predeterminado, sino de encontrar del conjunto de solucio- nes la éptima segiin unas restricciones definidas. En términos reales, este es el problema del viajante que tiene que hacer las maletas seleccionando entre 7 articulos, aquellos cuyo valor total sea un maximo (lo éptimo, en este caso, es e1 maximo establecido) y su peso no exceda de una cantidad. Seguimos aplicando la estrategia de vuelta atrés para generar todas las soluciones posibles, y cada vez que se alcance una solucién guardarla si es mejor que las solucio- nes anteriores segiin la restriccién definida. Af solucion then Af nejorisolucion) then eptino resolucio La tarea basica en esta biisqueda sistematica es investigar si un objeto i es adecuado incluirlo en la seleccién que se ira acercando a una solucién aceptable, y continuar la biisqueda con el siguiente objeto. En el caso de que lo que haya que hacer sea excluirlo 298 Estructura de datos de la seleccién actual, el criterio para seguir con el proceso de seleccién actual es que el valor total todavia alcanzable después de esta exclusién no sea menor que el valor épti- mo (maximo) encontrado hasta ahora. Cada tarea realiza las mismas acciones que la tarea anterior, por lo que puede expresarse recursivamente, Al estar buscando la selec- ccién éptima, hay que probar con todos los objetos del conjunto. Consideramos que el valor maximo alcanzable inicialmente es la suma de todos los, valores de los objetos que disponemos. Debido a la restriccién del peso, posiblemente el valor éptimo alcanzado sea menor. 9.6.1. El Suponemos que el viajante tiene 10 objetos. La entrada de datos es la informacién aso- ciada con cada objeto: . El peso maximo que puede ser transportado varia- 14 desde el minimo peso hasta el peso total de los objetos, con un incremento de 3 y un maximo de 10 salidas. EI valor maximo que pueden alcanzar los objetos es la suma de los valores de cada uno, esta representado por la variable valor. El valor éptimo alcanzado en el proceso transcurrido esti en la variable Mva lo: Los parametros del procedimiento recursivo son los necesarios para realizar una nueva tarea: 1, nlimero de objetos a probar; Pt, peso de la seleccién actual; Va, valor maximo alcanzable por la seleceién actual; y “valor, que es el valor maximo obtenido en el proceso transcurtido. jjante de comercio CODIFICACION program optima (input, output}: n= 10 type objeto = Recora array ce] of objeto; rvalor, Wvalor, procedure objetos (var Recursividad: algoritmos rocursivos 289 tv i= 0; tp r= 0; fork := 1 to N do begin verite(‘objeto', K,".', ‘Peso y valor:* FeadlniG(k] .pso,G{Ki .vall ; vie Ty + G(R) -vals Tp i= Tp + GLK) .pso ena ena function Hin(A:Lista) sinteser: K,Metnteger: begin M i= AlL].psor for K:= 2 to N do Af ALK)-pso |] then bestia write (‘Seleceion éptima:"}; for f := 1 to x do if kins then Write ("<",A(K) .pso.°, “AK -val,>")y writeln (Peso: ’,P, ‘Valor! ”,V) ena ena (21 procedimiento recursive, Maleta, es el que encuentra la seleccién éptina} procedure Maleta (I:indice; Pt, Varinteger;var Mvalor: integer); Vanx: integers begin Af Pe + AlT].pso tvalor then (Todos los objetos han sido probados y+ begin (se he obtenide un nuevo valor Sptino) opt r= act: mvalor i= va ena Act r= Act - [1] (Vuelta atrés para ensayar la exclusién} ena {Proceso de exclusién del objeto I para seguir ia bisqueda sistenética con #1 objeto Yel) 300 Estructura de datos xino que podria alcanzar 1a eeleceién actua if Vane > ‘valor then if TW then Maleta (I+1, Po, Vaex, Mvalor begin ena: superar el val imo actual: Nvalor} ends begin for := 1 to N do write (AIK) -ps0:8) weiteln weite (‘valor for K:- 1 to N ao write (AK)-valz61; writeln (21 peso mdxino ird variande desde el minimo, hasta alcanz: maxina 010 pruebas, cada prueba aumenta ef peso en 3 unidad: Tors Min(al: Pome := Tr Solueion P upti1 (2s0mx > Tpeso) oF (Psomx > Ts ona. 9.7. PROBLEMA DE LOS MATRIMONIOS ESTABLES EI planteamiento del problema es el siguiente: dados dos conjuntos A y B, disjuntos y con igual nimero de elementos, n, hay que encontrar un conjunto de m pares (a,b), tales que a pertenece A, b pertenece a B y cumplan ciertas condiciones. Una concrecién de este planteamiento es el problema de los matrimonios esta: bles. Ahora A es un conjunto de hombres y B un conjunto de mujeres. A la hora de clegir pareja, cada hombre y cada mujer tienen distintas preferencias. Se trata de for- ‘mar parejas, matrimonios estables. De las m parejas, en cuanto exista un hombre y ‘una mujer que no formen pareja pero que se preficran frente a sus respectivas parejas, se dice que la asignacién es inestable ya que tenderé a una ruptura para buscar la pre- ferencia comin, $i no existe ninguna pareja inestable se dice que la asignacién es es- table. Recursividad: algortmos recursivos 265 homélogos iterativos. Se puede, por tanto, afirmar que la efecucién de un programa recursivo va a ser mas lenta y menos eficiente que el programa iterativo que soluciona el mismo problema, aunque, a veces, la sencillez de la estructura recursiva justifiea el mayor tiempo de ejecucién. Los procedimientos recursivos se pueden convertir en no recursivos mediante la in- troduccién de una pila y asi emular las Hamadas recursivas. De esta forma se puede climinar la recursién de aquellas partes de los programas que se ejecutan més frecuente- mente. PROBLEMA 9.1 Dada una lista enlazada imprimirla en orden inverso. Se tiene una lista enlazada que se referencia por un puntero externo al primer nodo de la lista. Se desea imprimir los nodos del tiltimo al primero. Los tipos de datos que se utilizan en la lista son: type Nodo = record nto: Tpotnte: end; . ic > > al La variable L referencia al primer nodo de la lista. El problema va a ser descompues- to de forma recursiva, de tal forma que se vaya reduciendo la lista hasta Hegar al dltimo nodo. Es posible considerar la tarea a realizar dividida cn los siguientes pasos: ‘Imprimir desde el segundo nodo hasta el tiltimo en orden inverso. © Imprimir el primer nodo. Ya se ha reducido la lista en un nodo. A su vez, la primera parte se puede efectuar en dos pasos: © Imprimir desde el tercer nodo hasta el tiltimo en orden inverso. ‘© Imprimir el segundo nodo. El primer paso esti formulado recursivamente. El proceso llega a su fin cuando no quedan elementos en Ia lista. Rcursividad: algoritmos recursives 301 En el problema se hace la abstraccién de que la lista de preferencias no cambia al hacer una asignacién, Este planteamiento caracteriza ciertos problemas en los que hay dos conjuntos de elementos y se ha de hacer una eleccién segin una lista de preferencias. Asi, pensemos cen el conjunto de ofertas de vacaciones y el conjunto de turistas que quieren elegir una de ellas; la eleccién de facultad por los chicos de COU ALGORITMO Una forma de buscar solucién es aplicar la biisqueda sistemética de los algoritmos de «vuelta atris». La tarea bsica es encontrar una pareja para un hombre # segin la lista de preferencias, esta tarea basica la realiza el procedimiento ensayar: procedimiento Ensayar(H: TipoHonbr: inicio Desde < 1 hasta n hacer ‘STonar preferencia R-écima de hombre H> eL aceptable entoaces #1 entonces pnsayar (H+) sino Ahora afrontamos la tarea de representacion de datos. El Tipohombre, Tipomujer son representados por un subrango entero; por tanto, hacemos la abstraccién de repre- sentar tanto un hombre como una mujer por un néimero que es el ordinal del rango de hombres 0 de mujeres. Para representar las preferencias de los hombres por las mujeres se utiliza una matriz de mujeres. Reciprocamente, las preferencias de las mujeres por los hombres son representadas por una matriz. de hombres. La solueién del problema ha de ser tal que nos muestre las parejas (hombre-mujer) que forman la asignacién estable. Dos vectores, uno de las parejas de los hombres y el otro de parejas de las mujeres, representan 1a solucién, N=... 7 (Wimero de parejas) pohonbre = 1.4: Prefnombres = array [Tipchombre,1..N) of Tipomujer: refmujeres = array [Tip94 3] of Tipohonbre: Parhombres= array [Tipohorbre] of Tipomujer; 902 — Estructura de datos Parmujeres= array (Tipomujeres) of Pipchombre; Phb: Prefhonbree ji Pretmujeres; La informacién representada por V y F determina la estabilidad de un conjunto de ‘matrimonios. Este conjunto se construye paso @ paso casando hombre-mujer y compro- bando ta estabilidad después de cada propuesta de matrimonio. Para facilitar la inspec- cidn de las parejas ya formadas utilizamos un array l6gico: tera: array(Tipomujer] of bo Soltera [J] a true quiere decit que la mujer J todavia no ha encontrado pareja. Para determinar si un hombre K ha encontrado pareja puede utilizarse otro array similar al de Soltera, o bien sencillamente si X<_H es que K ya encontré pareja (H es el hombre actual que busca pareja). Con todas estas consideraciones de tipos de datos ya podemos proponer una solu- cién mas elaborada: procedimiento Ensayar|H: Tipolisnbre snteso PRD IH, 8 (iujer candiaata: ei solteralM) y SolieratM] © true final fin_procedimiento La accién mas importante que nos falta es determinar la estabilidad que ha sido expresada como . Pues bien, la buscada estabilidad se encuentra por com- paraciones entre las distintas preferencias. Las preferencias vienen dadas por el rango de I aN. Para facilitar el caleulo de la estabilidad son definidas dos matrices: Rha: array [Tipohombre, Tipons Rnht array [Tiporiser,Tipohonbre] ef 1..¥ Recursividad: algorimos recursivos 303 tal que Rhm(H,™] contiene el orden que ocupa, 0 rango, de la mujer M en Ja lista de preferencias del hombre #. De igual forma, Rh (Mf, #) contiene el orden del hombre H en la lista de preferencias de la mujer ¥. Ambas matrices se determinan inicialmente @ partir de las matrices de preferencias El predicado parte de la hipétesis de que lo normal es la estabilidad y se buscan posibles fuentes de perturbarla. Recordemos que se esté analizando la estabili- dad de la posible pareja H y M, siendo M la mujer que ocupa Ia posicién R en la lista de preferencias de (M << PhbLH, F]). Hay dos posibilidades: 1. Puede haber otra mujer Mm, por la que H tenga més preferencia que M, y a su vez Mm prefiera més a H que a su actual pareja. De forma simétrica 2. Puede haber otro hombre Hh, por el que M tenga més preferencia que a H, ya su vez ese hombre prefiera més a M que a su actual pareja. La posibilidad I se dilucida comparando los rangos Rhsm (34m, #) y Rmh (26m, F (26) ] para todas las mujeres mas preferidas que % por el hombre H. Es decir, para todas las Hm © Phb[H,] tales que I < R, Ademés, todas estas mujeres tienen ya parej ya que si alguna estuviera soltera el hombre # la hubiera elegido ya. Esta posibilidad puede expresars rel . nientras (I< R) y Estable hacer tn Phb(H,E si no soltera[Mn] entonces able © Amhiéis,#i < Rmit(Mst, P(Mm)] (Ee estable si prefiere mis fin_mientree Para analizar la posibilidad 2 razonamos de forma simétrica. Hay que investigar a todos los hombres Hh por los cuales tiene mas predileccién la mujer M que a su pareja, actual H ren © mh, i (a < Tope) y Estable hacer sith Rhn(Hh, V[Hhl) (Batable si dh pretiere fin_mientras La codificacién de estas dos posibles fuentes de inestabilidad la realizamos en una funci6n légica anidada al procedimiento ensayar. 304 Estructura de datos CODIFICACION program Matrinoniozstable: N= 9; {Ndmero de parejas a formar) type ipohombre = 1 .. Wy Tipomujer = 1 .. 8: Prefhombres = array (Tipohombre, 1..} of Tipomujers Prefmujeres = array (Tipomujer, 1.2] of Tipohombre; Parhombres = array [Tipchombre] of Tipomujer: Parmujeres = array (Tipomujer] of Tipohonbr: Flags = array(Tipomujer] of boolean: Matranghb » argay(Tipohonbre, ‘Tiponujer) of 1..N; Matrangni = array[Tipomujer, Tipchombre) of 1..N; Phb: Prefhombres: Paj: Prefmujeres: Vi Parhombres; Pi Parnujeres; Soltera: Flags: Bhm: Natranghb, Reh: Matrangn}: H: Tipohonbr Mi Tipomujers R: integer; procedure Escribir: Hs Tipohombre; begin Wwrite(*solueién: "1 for # i= 1 to Nao writes Hy uM, VID, ty writen ends procedure Ensayar(ii: Tipohombre) ; integer: M: Tipomijers function Estable (i: Tipohombre;¥:Tipomujer;R:integer) :boolean: ih: Tipohonbre: Min: ‘Pipomujer: I, Tope: integer; EG: boolean; begin Es t= truer Tied; while (I <8) and zs do begin Mo = PhbUH, I); Dez Qelr Recursividad: algoritmos recursivos 305 Af not Solcera (um) then Be r+ Rh (Mm, H] << Rmh(Mn, PM) | ena: Desay nope in Reb [.H): while (I < Tope) and Ee do begin Bh ss Pag (1); ret Af Gh © Hehe Ee i= Rbm[ih.M) > Rbm(Hh,V Hh) | ends Estable := gs ena; begin (Ensayar} for 8 i= 1 to N do begin Me PRDIK, RI) ie soltera(M) and sstable(H, m, R) then begin von) t= xe Fim] ie Soltera(M] := false: sei < N chen Ensayar(H + 1) else (Encontrada una asignacién estable } Escribir: soltera(M] := true end ena enay begin (blogue principal) (Entrada de rango de preferencias de hombres) for i := 1 te Nao begin writeln(*Preferencias de hombre ', Hy' segin rango de 2a‘, Ny tor i= 1 to 8 do begin ead(Pab(H, RI) Rhn(H, PRbIM, R]] s= R end ena; (gntrada de rango do preferencias de mujeres) fort :- 1 to Nao begin Writeln(‘Preferencias de mujer *, M,* segin rango de La, Wiz for § !- 1 to N do begin Fead(mj(M. RI} RobiM,Pms(M, RB) t= R ena ends for M i= 1 to N do Soltera(M) := true; Breayar (1) ona. 306 Estructura de datos RESUMEN La recursién (recursividad) permite resolver problemas cuyas soluciones iterativas son dificiles de conceptualizar: un procedimiento 0 funcién que se llama a si misma. Normalmente, una solu- cidn recursiva es menos eficiente en términos de tiempo y operaciones suplementarias que entra jian las llamadas extra a procedimientos; sin embargo, en numerosas ocasiones el uso de la recur- sién permite especificar una solucién muy natural y sencilla a problemas que en caso contrario serian muy dificiles de resolver. Por esta raz6n, la recursividad es una herramienta muy importan- te y potente para la resolucion de problemas con programacién, El uso apropiado de la recursividad se debe considerar antes de su utilizacién. Una vez toma. da la decisién, e! programador debe tener mucha precaucién en proporcionar condiciones de ter- ‘minacién para detener las llamadas recursivas. Es muy facil entrar en un buele infinito si no se incluyen condiciones de terminacién adecuadas. Algunos lenguajes de programacién no permiten la recursividad. Por consiguiente, un progra- ‘mador puede desear resolver un problema utilizando técnicas recursivas mediante el uso de pseu docédigo. Incluso, como en el caso de Pascal, que soporta recursividad, el programador puede tratar de intentar redueir las operaciones y el tiempo auxiliar implicado en el proceso recursive simulando la recursividad, EJERCICIOS 9.1. Suponer que la funcién G esté definida recursivamente de la siguiente forma: 1 sixs GK, vf * Gx-y+ D1 si yex Siendo x.y enteros positivos. 4a) Encontrar el valor de G (8,6). '6) Encontrar el valor de G (100,10). 9.2, Sea H(x) una funcién definida recursivamente ‘Vx > 0, siendo.x un entero: nef! six=l OTH 241 si x>1 4) Encontrar el valor de H(80). 5) {Cémo podemos describir lo que hace esta funcién? 9.3. Definimos C(x.) como el nimero de combinaciones de n elementos agrupados de ken k, es decir, el niimero de los diferentes grupos que se pueden formar con & miembros dado un Conjunto de n miembros para elegir. Asi, por ejemplo, sim = 4 ({,B,C,D}) C(4,2) = 6 que serdn: (A.B), (A.C), (A,D), (B.C), (B,D), (C.D), ‘mateméticamente C(n.k) podemos definirla: Cine n Cnn) = 1 Ck) = Chm 1, R= 1) + Cl 1, BY Yn > > 94, 95. 96. 97. 98. 99. 9.10. Recursivided: algoritmos recursivos 307 4) Encontrar el valor de C(8,5). ») Escribir una funcién recursiva para calcular C(x). Eliminar la recursividad de la funcién C(n,). Eseribir a funcién C(x, 4) de forma iterativa utilizando una pila para eliminar la recursividad. Dada la siguiente funcién recursiva function Re begin Teadich Af soln then WN integer): chars Roves += Reves (1); end: 4) {Qué hace la funcién? ») Hacer un seguimiento con esta llamada: Reves(1) Dado el siguiente procedimiento recursive: procedure Desconocido(N, Despi: integer! begin few > 0 then begin Desconocido(N-1, Despi+1 for x :- 1 to Despl do for K := 1 to Despl do writela: Desconeeido(i-1, Despl+1) ona ena: Hacer un seguimiento del procedimiento para la llamada Desconocido (4,1) Eliminar la recursividad del procedimiento escrito en 9.6. Escribir de nuevo el procedi- miento Desconocido del ejercicio 9.6 utilizando una pila Realizar una funcin recursiva que calcule la funcién de Ackermann definida de la siguien- te forma: A(mn) Acmn) A(mn) ntl sim=0 A(m-,1) sin ‘Alm-1A(mnl))— sim> Oy n>0 Escribir la funcién de Ackermann eliminando la recursividad, La resolucién recursiva de las Torres de Hanoi ha sido realizada con dos llamadas recursi- vas. Volver a escribir el procedimiento de resolucién con una sola llamada recursiva, ‘Nota: Sustitur la siltima llamada por un bucle repeti-hasta. 308 Estructura de datos PROBLEMAS ou. 92. 93. 9. 9s. 96. 9. En el problema de las 8 reinas se encuentran 92 soluciones diferentes. Hacer los cambios inecesarios en el procedimiento de resolucién para que nos muestre tinicamente las solucio- nes no simétricas. Escribir un programa que tenga como entrada una secuencia de numeros enteros positivos (mediante una variable entera). El programa debe de hallar la suma de los digitos de cada entero y encontrar cudl es el entero cuya suma de digitos es mayor. La suma de digitos ha de ser con una funcidn recursiva ‘Sea A una matriz.cuadrada de n * m elementos, el determinante de A podemos definirlo de a) Sin=1 entonces Deter(A) = ay, b)_ Para n > 1, el determinante es la suma alternada de productos de los elementos de una fila 0 columna elegida al azar por sus menores complementarios. A su vez, los menores complementarios son los determinantes de orden n-1 obtenidos al suprimir la fila y columna en que se encuentra el elemento, Podemos expresarlo: Det(A)= £ -1y/ *Aliy] * Det(Menor( Afi); para cualquier columna j ° Det $19"! * Been Ai): pa ae a Se observa que la resoluci Escribir un programa que tenga como entrada los elementos de la matriz A, y tenga como, salida la matriz A y el determinante de A. Eligiendo la fila para calcular el determinante. Escribir un programa que transforme niimeros enteros en base 10 a otro en base B. Siendo la base B de 8 a 16, La transformacin se ha de realizar siguiendo una estrategia recursiva, Escribir un programa para resolver el problema de la subsecuencia creciente més larga. La entrada es una secuencia de n nlimeros aj, a, ds, .. , dy; hay que encontrar la subsecuencia, mas larga aj, 3, dy tal QUE ay nia chen begin 9.2.1, Eliminacién de la recursividad Para eliminar la recursividad se utiliza una pila. En la pila el primer elemento que entra sel ultimo en salir. Por consiguiente habra que recorrer la lista, nodo a nodo. Las direc- cciones de los nodos (punteros) son almacenados en una pila hasta alcanzar el ltimo nodo. Una vez alcanzado el tiltimo nodo se escribe el campo de informacién y aqui es donde se simula la recursividad. La vuelta atrés conseguida con la recursividad se consi- gue sacando de la pila las direcciones de los nodos, escribiendo la informacién, asi hasta que quede vacia la pila Codificacién procedure Inpriueinverso (L: Puntere) + begin lal waile P <> ali do begin zn la pila estén todas las direcciones de los nodas while not Pyacia(Pila) ao begin Psacar(P, Pilal Escribirip™.tafo) end ena PROBLEMA 9.2 Multiplicacién de dos niimeros enteros por el método de la montaiia rusa Descripeién: El método consiste en formar dos columnas, una por cada operando, Las columnas se forman aplicando repetidamente los pasos siguientes. Recursividad: algoritmos recursivos 267 * Dividir por 2 el multiplicando. Anotar el cociente en ta columna del multiplican- do como nuevo multiplicando * Duplicar el multiplicador y anotarlo en la columna del multiplicador. Una vez hecho esto, se suman los valores de la columna del multiplicador que se correspondan con valores impares de la columna de multiplicandos. La suma es el pro- ducto. Codificacién EI problema se resuelve con una funcién que tiene como entrada dos enteros X, ¥, y devuelve el producto aplicando el método de la montatia usa, function Produ! begin fe x >< 1 then A€ (x mod 2) <> 0 then (4s impar) Producto ix ¥ + Praducto(x div 2, ¥* 2) peg eeeeteeesi = Producto(x ay 2, ¥ * 2) ena 9.3. ALGORITMOS «DIVIDE Y VENCERAS» Una de las técnicas mas importantes para el disefio de algoritmos recursivos es la téc- nica llamada «divide y venceras». Consiste esta técnica en transformar un problema de tamaito 7 en problemas mas pequefios, de tamafio menor que m. De modo que dando solucién a los problemas unitarios se pueda construir ficilmente una solucién del pro- bblema completo, El algoritmo de bisqueda binaria es un ejemplo tipico de esta técnica algoritmica. La lista ordenada de elementos se divide en dos mitades de forma que el problema de busqueda de un elemento se reduce al problema de bisqueda en una mitad; asi se pro- sigue dividiendo el problema hasta encontrar el elemento, o bien decidir que no se encuentra. Otro ejemplo claro de esta técnica es el método de ordenacién rapido (quick sort). Un algoritmo «divide y vencerés» puede ser definido de manera recursiva, de tal modo que se llama a si mismo aplicdndose cada vez a un conjunto menor de elementos. La condicién para dejar de hacer Ilamadas es, normalmente, la obtencién de un solo elemento, 9.3.1. Torres de Hanoi Este famoso juego/acertijo que a continuacién se describe, va a permitiraplicar la técni- ca de «divide y vencerds» en la resolucién de un problema. El juego dispone de tres 268 Estructura de datos postes, A, B, C; en el poste A se encuentran n discos de tamaio decreciente. El objetivo es mover uno a uno los discos desde el poste A al poste C utilizando el poste B como auxiliar, Ademés, nunca podré haber un disco de mayor radio encima de otro de menor radio. Vamos a plantear la solucién de tal forma que el problema se vaya dividiendo en problemas mas pequeftos, y a cada uno de ellos aplicarles la misma solucién. En lengua- {je natural lo podemos expresar asi L, El problema de mover 1 discos de A a C consiste en: ‘mover los n-I discos superiores de AaB mover el discon de A aC mover los n-I discos de B aC Un problema de tamaio 7 ha sido transformado en un problema de tama n-1. A su vez cada problema de tamaiio n-/ se transforma en otro de tamafio n-2 (empleando el poste libre como auxiliar). 2. El problema de mover los n-/ discos de A a B consiste en: ‘mover los n-2 discos superiores de A a C mover el disco n-1 de AaB ‘mover los n-2 discos de Ca B De este modo se va progresando, reduciendo cada vez un nivel la dificultad del pro- blema hasta que el mismo s6lo consista en mover un solo disco. La técnica consiste en ir intercambiando a finalidad de los postes, origen destino y auxiliar. La condicién de terminacién es que el mimero de discos sea 1. Cada accién de mover un disco reatiza los ismos pasos, por lo que puede ser expresada de manera recursiva El procedimiento recursivo Torr esH resuelve el acertijo o juego. procedure Torr procedure vo" begin end: eH (Mr integer: A, B tae ast a 0) Recursivided: algortmos recursivos 269 begin fe et then Movimiento (¥, A, Cl else begin Torres (N- 1, A, C, BV: end ena 9.3.2. Traza de un segmento Se desea dibujar un segmento que conecta dos puntos (x1, yl) y (+2, y2). Suponemos que siempre x1, yl, x2, y2 son > = 0. Planteamos la solucién de manera recursiva, utili- zando la estrategia «divide y venceras». El procedimiento consiste en dibujar el punto ‘medio del segmento; sobre ias dos mitades que determina ese punto medio volvemos @ aplicar el algoritmo de dibujar su punto medio. Asi hasta que, a base de dividir el seg- mento, se proporcione un segmento de longitud préxima a cero. El programa Dibujar en el que se define el tipo de dato coordenada (coord), se cestablecen los extremos del segmento y se dibuja program Dibujary Coord = record Ki real vt real ena: 0, Ft Coord: procedure Div_santo(o, Fr Coord): Mz coords vegin AE (0.X+0.5) < Pox then begin ¥ te (OLYsPL¥I/2 Dib_sgmto lO, M): Af wnerex > 70 then cotoxy (5, where = 1); webeec C ked2t, t,o ¥e8E Le) Y Dib_eemeotm, FI; ona end, begin O.K te Ly OY re 2 Fix ied; Bay = 7 Dib_agatolo, F) ena 270 Estructura de datos 9.4. IMPLEMENTACION DE PROCEDIMIENTOS RECURSIVOS MEDIANTE PILAS Un procedimiento, una funcién contiene tanto variables locales como argumen- tos ficticios (pardimetros). A través de los argumentos se transmiten datos en las llama- das a los subprogramas, 0 bien se devuelven valores al programa o subprograma in- vocante. ‘Ademés, el subprograma debe guardar la direccién de retorno al programa que reali- za a llamada. En el momento en que termina la ejecucién de un subprograma el control pasa a la direccién guardada ‘Ahora el subprograma es recursivo, entonces ademés de la direccién de retorno, los valores actuales de las variables locales y argumentos deben de guardarse ya que se usarén de nuevo cuando el subprograma se reactive. Supongamos que se ha llamado al subprograma P, que tiene llamadas a si mismo, es decir, es recursivo. El funcionamiento del programa recursivo P: ‘© Se crea una pila para cada argumento, ‘© Se crea una pila para cada variable local, Se crea una pila para almacenar la direccién de retorno, Cada vez que se hace una llamada recursiva a P, los valores actuales de los argumen- tos y de las variables locales se meten en sus pilas para ser procesadas posteriormente. Asimismo, cada vez que hay un retorno @ P procedente de una llamada recursiva ante- rior, se restauran los valores de variables locales y argumentos de las cimas de las pilas. Para la obtencién de la direccién de retorno vamos a suponer que el procedimiento > contiene una llamada recursiva en la sentencia N. Entonces guarda en otra pila la direc- 6n de retorno, que sera la sentencia siguiente, la 8) + 1. De tal forma que cuando el nivel de ejecucién del procedimiento P actual termine, alcance la sentencia end final, usaré dicha pila de direcciones para volver al nuevo nivel de ejecucién. De esta forma cuando la pila de direcciones se quede vacia volverd al programa que llamé al subpro- ‘grama recursivo, PROBLEMA 9.3 Hacemos una traza del estado de las pilas en la ejecucién de funcién producto, por el ‘método de la montaita rusa, para los valores de 19 y 45. 720 7204Prod 1 2 360 ProductoO. 4 180. Producto. 9 90 90+Prod. 9 45 _454+Prod Pla Pila de deX — deY direc.

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