336
EXÁMENES RESUELTOS PROGRAMACIÓN III

Examenes resueltos

Embed Size (px)

Citation preview

Page 1: Examenes resueltos

EXÁMENES

RESUELTOS

PROGRAMACIÓN III

Page 2: Examenes resueltos

Recopilación de Exámenes de Programación III

Esta recopilación de exámenes incluye desde el año 1996 hasta septiembre de 2008. Llevo unos dos años haciéndola y no hubiera sido posible sin la inestimable ayuda de Ali, por ello creí conveniente nombrarla ya que ha sido de gran ayuda en la resolución de problemas y dudas que han hecho posible esta colección de exámenes.

Antonio Rivero Cuesta Alicia Sánchez Ferro

Palma de Mallorca, septiembre de 2008

Page 3: Examenes resueltos

Problemas de Programación III Febrero 1996-1..................Calcular 2( ) 2T n n= ................................... Divide y Vencerás Febrero 1996-1..................Calcular recubrimiento de vértices................ Voraz Febrero 1996-2..................Dominó ......................................................... Vuelta Atrás Febrero 1996-2..................Fibonacci....................................................... Divide y Vencerás Septiem 1996 ....................Cartógrafo ..................................................... Voraz Septiem 1996 ....................Calcular 2 = d(d(m(d(7)))) ............................ Vuelta Atrás Septiem 1996-R ................f x c Alumnos ................................................ Divide y Vencerás Septiem 1996-R ................Seleccionar carreteras ................................... Voraz Febrero 1997-1..................n Cintas n Registros ...................................... Voraz Febrero 1997-1..................El 31. ............................................................. Vuelta Atrás Febrero 1997-2..................Grabar n Canciones....................................... Voraz Septiem 1997 ....................n Motos n Clientes ........................................ Ramificación y Poda Septiem 1997 ....................Tablero .......................................................... Vuelta Atrás Febrero 1998-1..................El Continental. .............................................. Vuelta Atrás Febrero 1998-1..................Metro Japón. ................................................. Voraz Febrero 1998-2..................Línea Horizonte ............................................ Voraz Febrero 1998-2..................Mecano 8 piezas............................................ Ramificación y Poda Septiem 1998 ....................n rectángulos ................................................. Voraz Septiem 1998 ....................Cadena euleriana........................................... Voraz Febrero 1999-1..................Nave Mir. ...................................................... Ramificación y Poda Febrero 1999-1..................Colorear 3 colores. ........................................ Vuelta Atrás Febrero 1999-2..................Mínimo Colores ............................................ Vuelta Atrás Febrero 1999-2..................Liga n equipos............................................... Divide y Vencerás Febrero 2000-1..................Tablero Genérico........................................... Vuelta Atrás Febrero 2000-2..................Base Aerea .................................................... Ramificación y Poda Septiem 2000 ....................Mayoritario ................................................... Divide y Vencerás Febrero 2001-1..................Río Guadalhorce ........................................... Vuelta Atrás, Ramificación y Poda Febrero 2001-2..................Torneo n participantes................................... Divide y Vencerás Septiem 2001 ....................Tablero .......................................................... Vuelta Atrás, Ramificación y Poda Febrero 2002-1..................Caja de Bombones ........................................ Divide y Vencerás Febrero 2002-2..................8 casillas........................................................ Vuelta Atrás Septiem 2002 ....................Laberinto ....................................................... Ramificación y Poda Septiem 2002-R ................Buscaminas ................................................... Divide y Vencerás Diciem 2002.....................Multiplicación de polinomios ....................... Vuelta Atrás Febrero 2003-1..................Laberinto ....................................................... Vuelta Atrás Febrero 2003-2..................Fibonacci....................................................... Divide y Vencerás Septiem 2003 ....................Operadora Teleco.......................................... Voraz Septiem 2003-R ................Daniel Tesoros .............................................. Ramificación y Poda Diciem 2003.....................Taller Sleepy ................................................. Voraz Febrero 2004-1..................Matriz de 3 colores........................................ Vuelta Atrás Febrero 2004-2..................Grafo dirigido................................................ Recorrido profundidad Septiem 2004 ....................Vectores texto ............................................... Ramificación y Poda Septiem 2004-R ................n Agentes n Tareas........................................ Ramificación y Poda Febrero 2005-1..................Conjunto operaciones.................................... Vuelta Atrás Febrero 2005-2..................Estructura Montículo..................................... Divide y Vencerás Septiem 2005 ....................Votación Elecciones...................................... Divide y Vencerás Septiem 2005-R ................Sudoku .......................................................... Vuelta Atrás Febrero 2006-1..................n montadores................................................. Ramificación y Poda Febrero 2006-2..................Dos socios ..................................................... Vuelta Atrás Septiem 2006 ....................Salto caballo.................................................. Vuelta Atrás Septiem 2006-R ................Repartidor de Pizzas...................................... Voraz Diciem 2006......................Grabación Cd ................................................ Ramificación y Poda Febrero 2007-1..................Taller Sleepy ................................................. Voraz Febrero 2007-2..................Suma exacta C............................................... Vuelta Atrás Septiem 2007 ....................n objetos volumen ......................................... Ramificación y Poda Septiem 2007-R ................Parejas estables ............................................. Vuelta Atrás Febrero 2008-1..................n Huertas ....................................................... Ramificación y Poda Febrero 2008-2..................n Agentes n Tareas........................................ Ramificación y Poda Septiem 2008 ....................n Agentes n Tareas........................................ Ramificación y Poda Septiem 2008-R ................n Agentes n Tareas........................................ Ramificación y Poda

Page 4: Examenes resueltos
Page 5: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero

Examen primera semana - Curso 1995-96

Problema 1 (5 puntos). El tiempo de ejecucion de un algoritmo viene dadopor T (n) = 2n

2

. Encontrar una forma eciente de calcular T (n), suponiendo queel coste de multiplicar dos enteros es proporcional a su tama~no en representacionbinaria.

Problema 2 (5 puntos). Un recubrimiento de vertices de un grafo no dirigidoG = hV;Ai es un conjunto de vertices tales que cada arista del grafo incide en,al menos, un vertice de V. Dise~nar un algoritmo que, dado un grafo no dirigido,calcule un recubrimiento de vertices de tama~no mnimo para un grafo dado.

La resolucion de cada problema debe incluir:

Eleccion razonada del esquema algortmico.

Descripcion del esquema usado e identicacion con el problema.

Estructuras de datos.

Algoritmo completo a partir del renamiento del esquema general.

Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Vuelta atras: descripcion del arbol de busqueda asociado.

Page 6: Examenes resueltos
Page 7: Examenes resueltos
Page 8: Examenes resueltos
Page 9: Examenes resueltos
Page 10: Examenes resueltos
Page 11: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1996 (Primera Semana) Problema 2 (5 puntos). Un recubrimiento R de vértices de un grafo no dirigido G = +N,A, es un conjunto de vértices tales que cada arista del grafo incide en, al menos, un vértice de R. Diseñar un algoritmo que, dado un grafo no dirigido, calcule un recubrimiento de vértices de tamaño mínimo. Solución: Elección razonada del esquema El esquema voraz se adapta perfectamente al problema, ya que: • Se trata de un problema de optimización: No solo hay que encontrar un recubrimiento, sino que

éste ha de ser de tamaño mínimo. • De entre un conjunto de vértices (candidatos) hay que seleccionar un subconjunto que será la

solución. Solo hay que encontrar la función de selección adecuada (si existe) para resolver el problema mediante un algoritmo voraz.

El esquema de divide y vencerás es descartable, pues no hay forma obvia de dividir el problema en subproblemas idénticos cuyas soluciones puedan combinarse en una solución global. El esquema de vuelta atrás es un esquema muy general y casi siempre muy costoso que no debemos usar si podemos dar un algoritmo voraz que resuelva el problema. Esquema general e identificación con el problema El esquema voraz se aplica a problema de optimización. Consiste en ir seleccionando elementos de un conjunto de candidatos que se van incorporando a la solución. Se caracterizan porque nunca se deshace una decisión ya tomada: los candidatos desechados no vuelven a ser considerados y los incorporados a la solución permanecen en ella hasta al final del algoritmo. Es crucial determinar la función de selección adecuada que nos asegure que la solución obtenida es óptima. Esta notación algorítmica puede escribirse así (libro de Brassard página 214): fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← elemento que maximiza objetivo (x) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun donde: C: Conjunto de vértices del grafo. S: Recubrimiento del grafo. La forma más “intuitiva” de garantizar que el recubrimiento sea mínimo es tomar vértices de los que salgan muchas aristas, esto es, elegir vértices con mayor grado. La función de selección debe escoger el candidato con más vértices de los que aun están en el conjunto de candidatos. Para ello, cada vez que seleccionemos un vértice tendremos que disminuir en uno el grado de cada uno de los vértices candidatos con el. Hay que seguir los siguientes pasos:

1. Elegir el vértice de mayor grado. 2. Recorrer su lista asociada (aquellos vértices con los que está conectado) y restar 1 al grado de

cada uno de ellos en el campo correspondiente en el vector de vértices.

Page 12: Examenes resueltos

De esta forma, cuando el grado de todos los candidatos sea cero todas las aristas del grafo tocan al conjunto de selección y será, por tanto, un recubrimiento. Según este criterio, las funciones del esquema principal tendrán el siguiente significado:

1. solución(S): Todas las aristas del grafo tocan al menos un vértice de S. 2. objetivo(x): Grado del vértice. 3. factible(S) (o completable): Siempre es cierto, ya que se selecciona cada vez un único vértice

correcto. En estos problemas añadimos la demostración de optimalidad, que será el siguiente: Este problemas es un ejemplo de que los algoritmos voraces, en determinadas ocasiones, no proporcionan la solución óptima, aunque si una buena aproximación a la misma. Ocurre también en el ejemplo que se cita en el capítulo de metodología del texto con el algoritmo de devolución de monedas en el sistema británico antiguo. Aunque la intuición nos indique, a veces una heurística que “no puede fallar”, un sencillo contraejemplo nos puede hacer ver más claramente lo dificultoso, a veces, del estudio de algoritmia. Se deja al lector que busque dicho contraejemplo para este caso. Estructuras de datos En el problema intervienen grafos, vértices de un grafo y conjunto de vértices. Para representar el grafo podemos utilizar cualquiera de las dos formas habituales, teniendo en cuenta que el uso de la matriz de adyacencia hará menos eficiente el algoritmo. Aquí representar el grafo como un vector de vértices, teniendo asociado cada vértice una lista enlazada con los vértices adyacentes a éste. Como los costes no juegan ningún papel en el algoritmo, lo excluiremos (por comodidad) de la estructura de datos. grafo = vértice [1..N] de vértice vertice = tupla indice: entero // Posición en el vector grado: entero // Grado del vértice adyacentes: apuntador a nodo_adyacente nodo_adyacente = tupla adyacente: entero siguiente: apuntador a nodo_adyacente Algoritmo completo a partir del refinamiento del esquema Adaptamos el algoritmo general a lo dicho anteriormente: fun recubrimiento-minimo (G: grafo) dev (S: conjunto de vértices) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← elemento que maximiza objetivo (x) C ←C \ x disminuir-grado (x,C) dev S ffun Las funciones son las siguientes: Solución: El conjunto S será una solución cuando el grado de todos los elementos que restan en C será cero. Será en pseudocódigo así:

Page 13: Examenes resueltos

fun solución (C: Conjunto de vértices) dev (b:booleano) b ← cierto para c en C hacer si G[i].grado ≠ 0 hacer b ← (G[i].grado =0) fpara dev b ffun Tal como comentábamos anteriormente, las soluciones aportadas en estos ejercicios hay algunas que no cuadran, debido a sintaxis, debido a que no es “entendible”, etc etc. En este caso, es una de ellas, ya que dentro del bucle “para” hay un bucle “si” que no comprendo muy bien que hace, por lo que calculamos la variable b (que es un booleano) para averiguar si es solución o no. Cabe destacar que la solución no es mía personal, la aporto otro compañero en los cursos virtuales, por ello gracias ;) La función de selección devuelve el grado del vértice en consideración: fun seleccionar (v: vertice) dev (g:entero) dev vertice.grado ffun Por último, la función disminuir-grado resta 1 al grado de todos los elementos conectados con el vértice elegido: fun disminuir_grado(v: vértice, C) para w ∈ C en sucesores (v) hacer w.grado ← w.grado - 1 fpara ffun Análisis del coste El tamaño del problema viene dado por el número de vértices del grafo. El número de veces que se ejecuta el bucle voraz es, en el peor de los casos, n. Dentro del bucle se realizan dos operaciones: encontrar el vértice de mayor grado, que tiene un coste lineal y disminuir en uno el grado de los demás, que tiene también coste lineal. De modo que el coste del bucle es Ο(n) y el coste del algoritmo es Ο(n2)

Page 14: Examenes resueltos
Page 15: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero

Examen segunda semana - Curso 1995-96

Problema 1 (5 puntos). Las 28 chas de domino son de la forma (i; j) coni; j = 1 : : : 6. Una cha de domino puede colocarse a continuacion de la anteriorsi coinciden los valores de los extremos que se tocan. Por ejemplo, a continuacionde la cha (1; 2) puede colocarse la (2; 4). Dise~nar un algoritmo que produzcatodas las cadenas permisibles que contengan todas las chas del domino.

Problema 2 (5 puntos). Dada la sucesion denida como fn = afn3 + bfn2 +cfn1 se pide dise~nar un algoritmo que calcule en tiempo logartmico el terminofn.Sugerencia: Utilizad la siguiente relacion:

0B@

0 1 00 0 1a b c

1CA

0B@

fn3fn2fn1

1CA =

0B@

fn2fn1fn

1CA

La resolucion de cada problema debe incluir:

Eleccion razonada del esquema algortmico.

Descripcion del esquema usado e identicacion con el problema.

Estructuras de datos.

Algoritmo completo a partir del renamiento del esquema general.

Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Vuelta atras: descripcion del arbol de busqueda asociado.

Page 16: Examenes resueltos
Page 17: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Septiembre 96

Examen Original

Problema 1 (5 puntos). Un cartografo acaba de terminar el plano de su pais,que incluye informacion sobre las carreteras que unen las principales ciudades ysus longitudes. Ahora quiere a~nadir una tabla en la que se recoja la distanciaentre cada par de ciudades del mapa (entendiendo por distancia la longitud delcamino mas corto entre las dos). Escribir un algoritmo que le permita realizaresa tabla.

Problema 2 (5 puntos). Se consideran las funciones m(x) = 3x y d(x) = x2(donde `' representa la division entera). Dise~nar un algoritmo que, dados dosnumeros a y b, encuentre una forma de llegar de a a b mediante aplicacionessucesivas de m y d. Por ejemplo, se puede pasar de 7 a 2 mediante

2 = d(d(m(d(7))))

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Vuelta atras: descripcion del arbol de busqueda asociado.

Page 18: Examenes resueltos
Page 19: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III

Soluciones a los examenes de Septiembre

Equipo docente de la asignatura

Problema

Un cartografo acaba de terminar el plano de su pais que incluye informacion sobrelas carreteras que unen las principales ciudades y sus longitudes Ahora quiereanadir una tabla en la que se recoja la distancia entre cada par de ciudades delmapa entendiendo por distancia la longitud del camino mas corto entre las dosEscribir un algoritmo que le permita realizar esa tabla

Eleccion razonada del esquema algortmico

Para hallar la distancia mnima desde un vertice de un grafo a cada uno de los demas verticescontamos con el algoritmo voraz de Dijkstra Basta pues con aplicarlo para cada una delas ciudades siendo estas los vertices las carreteras las aristas del grafo y sus longitudes lospesos de las aristas

Cuidado no hay que confundir este problema llamado de caminos mnimos con el problema de

dar un arbol de expansion mnimo que resuelven algoritmos como el de Prim o Kruskal En este caso

un arbol de expansion mnimo sera un subconjunto de carreteras que conectara todas las ciudades y

cuya longitud total fuera mnima pero esa condicion no nos asegura que la distancia entre cada par de

ciudades sea la mnima posible Pensad contrajemplos en caso de duda

Page 20: Examenes resueltos

Descripcion del esquema usado e identicacion con el problema

Nos ahorramos la explicacion que podeis encontrar en el BrassardBratley pag

Estructuras de datos

El conjunto de ciudades y carreteras viene representado por un grafo no orientado conpesos Podemos implementarlo como una matriz de adyacencia como una lista de listasde adyacencia etc

Ademas necesitaremos otra matriz que acumule las distancias mnimas entre ciudades yque sirva como resultado

Algoritmo completo a partir del renamiento del esquema general

La unica variacion respecto al algoritmo de Dijkstra es que necesitamos saber la distanciamnima entre cada par de ciudades no solo entre una ciudad y todas las demas Por ello esnecesario aplicar Dijkstra n veces siendo n el numero de ciudades en rigor no es necesarioaplicarlo sobre la ultima ciudad pues los caminos mnimos a esa ciudad ya han sido obtenidosen aplicaciones anteriores

fun mapa ggrafo dev vector N N de enterom vector N Npara cada vertice v hacer

m dijkstragvmfpara

dev mfun

donde el algoritmo de dijkstra se implementa mediante una funcion dijkstragvm quedevuelve la matriz m con la informacion anadida correspondiente a las distancias entre elgrafo v y todos los demas grafos de g

Estudio del coste

El coste del algoritmo depende de la implementacion para grafos que se escoja Si se implementa como una matriz de adyacencia sabemos que el coste del algoritmo de Dijkstra escuadratico On Como hemos de aplicarlo n veces o n que tambien es de orden nel coste del algoritmo completo es On

Page 21: Examenes resueltos

Problema

Se consideran las funciones mx x y dx x donde representa ladivision entera Disenar un algoritmo que dados dos numeros a y b encuentreuna forma de llegar de a a b mediante aplicaciones sucesivas de mx y dx Porejemplo se puede pasar de a mediante

ddmd

Como este problema esta en relacion muy estrecha con la practica del curso no ofrecemos

todava la solucion

Problema

En una clase hay f las y c columnas de pupitres Delante de la primera la seencuentra la pizarraa Disenar un algoritmo que reparta los f c alumnos de forma que al mirar haciala pizarra ninguno se vea estorbado por otro alumno mas alto que elb A mitad de curso se coloca una pizarra adicional en una de las paredes adyacentescon la primera pizarra Disenar un algoritmo que coloque a los alumnos de formaque puedan mirar tambien a esa segunda pizarra sin estorbarse Este algoritmo debesacar partido de la colocacion anterior

Eleccion razonada del esquema algortmico

Para que nadie tenga un alumno mas alto que el al mirar a la pizarra es necesario quedentro de cada columna los alumnos esten ordenados segun su altura de mayor a menor

Page 22: Examenes resueltos

Para resolver el apartado a de forma eciente basta con dividir los f c alumnos en csubconjuntos de f elementos escogidos al azar y a continuacion debe ordenarse cada unode esos subconjuntos Cada uno de ellos sera una columna en la clase Como algoritmode ordenacion puede escogerse cualquiera de los estudiados nosotros utilizaremos el algoritmo divide y venceras de fusion por ser mas eciente asintoticamente en el caso peor esOn logn

Al colocar una segunda pizarra adyacente a la primera los alumnos de cada la debenestar a su vez ordenados entre s Para que esten ordenadas las columnas y las las esnecesario ordenar a todos los alumnos de menor a mayor y colocarlos en la clase de formaque el mas bajito ocupe el pupitre que esta en la interseccion de las dos pizarras y el mas altoen el vertice opuesto de la clase Por lo tanto para obtener la disposicion nal de los alumnosen el apartado b debe hacerse una ordenacion de f c elementos Pero si aprovechamos ladisposicion anterior no es necesario esta vez aplicar ningun algoritmo de ordenacion bastacon realizar una fusion de los c subconjuntos ya ordenados equivaldra al ultimo paso de unalgoritmo de ordenacion por fusion en el que el factor de division fuera c As la ordenacionnal puede obtenerse en tiempo lineal

Descripcion del esquema usado e identicacion con el problema

El esquema divide y venceras es una tecnica recursiva que consiste en dividir un problemaen varios subproblemas del mismo tipo Las soluciones a estos subproblemas se combinan acontinuacion para dar la solucion al problema Cuando los subproblemas son mas pequenosque un umbral prejado se resuelven mediante un algoritmo especco Si su tamano esmayor se vuelven a descomponer El esquema es el siguiente

fun divide y venceras problemasi sucientementesimple problemaentonces dev solucionsimple problemasi no hacer

f p pk g descomposicionproblemapara cada si hacer si divide y venceraspi fpara

dev combinacions skfsi

un

Tamano umbral y solucion simple El preorden bien fundado para los problemas se derivadirectamente del orden total entre el tamano de los subconjuntos problema Podemos tomarcomo tamano umbral n caso en el que la ordenacion es trivial y consiste simplemente endevolver el elemento

Page 23: Examenes resueltos

Descomposicion Dividiremos el conjunto problema en dos subbconjuntos formados por losn primeros elementos por un lado y el resto por otro Combinacion Es necesario fundirlos dos subconjuntos ordenados mediante un bucle que toma cada vez el menor elemento deentre los primeros de uno y otro subconjunto todava sin seleccionar

Estructuras de datos

La unica estructura de datos que necesitamos es una matriz de enteros de tamano c f quealmacene las alturas de los alumnos Tambien podemos utilizar un vector de tamano c f sabiendo que cada f elementos representan una columna

Algoritmo completo a partir del renamiento del esquema general

Llamaremos a a la funcion que obtiene la ordenacion requerida en el apartado a y b a laque soluciona el apartado b es decir obtiene una ordenacion total a partir de la que setiene en a

La funcion a es la siguiente

fun a clase vector f c de enteros dev vector f c de enterospara i hasta c hacer

clase f i ordenacionclase f ifpara

dev claseun

La funcion de ordenacion equivale a la funcion general divide y venceras que modicaremos ligeramente para incluir como argumento vectores que sean siempre del mismo tamano

proc ordenacion v vector n ij entero dev vector nsi i jentonces dev vsi no hacer

k i j ordenacion vik ordenacion vkj fusion vij

fsi

fproc

Page 24: Examenes resueltos

La funcion de fusion tiene cuatro parametros el vector el principio y nal del tramo quecontiene a los dos subvectores que hay que fusionar y el factor de division empleado Parael apartado a podramos ahorrarnos este ultimo argumento es pero esa generalizacionnos permitira usar la misma funcion en el apartado b

proc fusion v vector n inicionalfactor entero dev vector nf Inicializa el vector solucion gv vector nf Inicializa punteros al comienzo de los vectores por fusionar gpara k hasta factor hacer

ik inicio factor k fpara

I f i ifactor gf Selecciona el menor elemento de entre los principios de vector

para incluirlo en la solucion y a continuacion lo borra paraque no vuelva a ser considerado gpara hinicio hasta nal hacer

ix elemento que maximiza vixvh vixsi ix inicio factor x hacer ix ix si no hacer I I n f ix g

fsi

fpara

v vfproc

La funcion b debe conseguir una ordenacion completa del conjunto de alumnos pero debetener en cuenta que ya existe una ordenacion parcial entre ellos los alumnos de cada columnaestan ordenados entre s Si representamos el conjunto de los alumnos como un vector decf elementos en el que los f primeros elementos corresponden a la primera columna los fsiguientes a la segunda etc el problema queda solucionado llamando a la funcion de fusiondenida anteriormente pero utilizando un factor de division c en lugar de

proc b v vector cf entero c dev vector cffusion vcfcfproc

Page 25: Examenes resueltos

Estudio del coste

apartado a

La ordenacion por fusion tiene un coste que cumple

T n T n cte n

ya que el algoritmo de fusion tiene un coste On consta de dos bucles consecutivos Deesa igualdad se obtiene un coste On logn Como se realizan c ordenaciones de f elementoscada una el coste total es Ocf log f Mediante una ordenacion total habramos resueltotambien el problema pero con un coste Ocf log cf ya que el tamano del problema serac f

apartado b

Se resuelve mediante una llamada al algoritmo de fusion que tiene un coste lineal comoel tamano del problema es c f el coste es Oc f El coste es mucho menor que en el casoen que no aprovecharamos la ordenacion parcial que se obtiene en el apartado a

Problema

Se planea conectar entre s todos los pueblos de una cierta region mediante carreterasque sustituyan los antiguos caminos vecinales Se dispone de un estudio que enumeratodas las posibles carreteras que podran construirse y cual sera el coste de construircada una de ellas Encontrar un algoritmo que permita seleccionar de entre todaslas carreteras posibles un subconjunto que conecte todos los pueblos de la regioncon un coste global mnimo

Eleccion razonada del esquema algortmico

Si interpretamos los datos como un grafo en el que los pueblos son los vertices y las carreterasson aristas cuyos pesos son el coste de construccion el problema no es otro que el de hallarun arbol de expansion mnimo para ese grafo En efecto un arbol de expansion mnimo esun conjunto de aristas que conectan todos los vertices del grafo en el que la suma de lospesos es mnima por tanto el coste de construir el subconjunto de carreteras es mnimo

Page 26: Examenes resueltos

Para resolverlo podemos usar cualquiera de los dos algoritmos voraces estudiados queresuelven este problema el de Kruskal o el de Prim

Cuidado No debe confundirse este problema con el de encontrar los caminos mnimos entre un

vertice y el resto Ver problema

Descripcion del esquema usado e identicacion con el problema

Nos ahorramos la descripcion del resto del problema Podeis encontrarla en la pagina del Bras

sardBratley

Page 27: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III Convocatoria de Septiembre

Examen de reserva

Problema puntos En una clase hay f las y c columnas de pupitresDelante de la primera la se encuentra la pizarraa Disenar un algoritmo que reparta los f c alumnos de forma que al mirarhacia la pizarra ninguno se vea estorbado por otro alumno mas alto que elb A mitad de curso se coloca una pizarra adicional en una de las paredes adyacentes con la primera pizarra Disenar un algoritmo que coloque a los alumnosde forma que puedan mirar tambien a esa segunda pizarra sin estorbarse Estealgoritmo debe sacar partido de la colocacion anterior

Problema puntos Se planea conectar entre s todos los pueblos de unacierta region mediante carreteras que sustituyan los antiguos caminos vecinalesSe dispone de un estudio que enumera todas las posibles carreteras que podranconstruirse y cual sera el coste de construir cada una de ellas Encontrar unalgoritmo que permita seleccionar de entre todas las carreteras posibles un subconjunto que conecte todos los pueblos de la region con un coste global mnimo

La resolucion de cada problema debe incluir por este orden

Eleccion razonada del esquema algortmico

Descripcion del esquema usado e identicacion con el problema

Estructuras de datos

Algoritmo completo a partir del renamiento del esquema general

Estudio del coste

Segun el esquema elegido hay que especicar ademas

Voraz demostracion de optimalidad

Divide y venceras preorden bien fundado

Vuelta atras descripcion del arbol de busqueda asociado

Page 28: Examenes resueltos
Page 29: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero de 1997

Examen primera semana

Problema 1 (5 puntos). Dado un conjunto de n cintas con ni registros or-denados cada una, se pretende mezclarlas a pares hasta lograr una unica cintaordenada. La secuencia en la que se realiza la mezcla determinara la ecienciadel proceso. Dise~nar un algoritmo que busque la solucion optima minimizando elnumero de movimientos.

Por ejemplo: 3 cintas: A con 30 registros, B con 20 y C con 10

1. Mezclamos A con B (50 movimientos) y el resultado con C (60 movimien-tos), con lo que realizamos en total 110 movimientos

2. Mezclamos C con B (30 Movimientos) y el resultado con A (60). Total =90 movimientos

>Hay alguna forma mas eciente de ordenar el contenido de las cintas?

Problema 2 (5 puntos). El juego del 31 utiliza las cartas de la baraja espa~nola:1,2,3,4,5,6,7,10(sota),11(caballo) y 12(rey) con los 4 palos: oros, copas, espadasy bastos. Dise~nar un algoritmo que calcule todas las posibles formas de obtener31 utilizando a lo sumo 4 cartas y 2 palos distintos en cada combinacion.

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Vuelta atras: descripcion del arbol de busqueda asociado.

Page 30: Examenes resueltos
Page 31: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1997 (Primera Semana) Problema 1 (5 puntos). Dado un conjunto de n cintas no vacías con ni registros ordenados cada uno, se pretende mezclarlos a pares hasta lograr una única cinta ordenada. La secuencia en la que se realiza la mezcla determinara la eficiencia del proceso. Diséñese un algoritmo que busque la solución óptima minimizando el número de movimientos. Por ejemplo: 3 cintas: A con 30 registros, B con 20 y C con 10. 1. Mezclamos A con B (50 movimientos) y el resultado con C (60 movimientos), con la que realiza en total 110 movimientos. 2. Mezclamos C con B (30 movimientos) y el resultado con A (60 movimientos), con la que realiza en total 90 movimientos. ¿Hay alguna forma más eficiente de ordenar el contenido de las cintas? Solución: Elección razonada del esquema El problema presenta una serie de elementos característicos de un esquema voraz: • Por un lado, se tienen un conjunto de candidatos (las cintas) que vamos eligiendo uno a uno hasta

completar determinada tarea. • Por otro lado, el orden de elección de dichos elementos determina la optimalidad de la solución,

de manera que para alcanzar una solución óptima es preciso seleccionar adecuadamente al candidato mediante un criterio determinado. Una vez escogido, habremos de demostrar que nos lleva a una solución óptima.

El criterio de elección de las cintas para alcanzar una solución óptima será el de elegir en cada momento aquella con menor número de registros. Demostración de optimalidad: La demostración corresponde con la de minimización del tiempo en el sistema, dada ya en ejercicios antes, por lo que evitamos escribirla de nuevo. Esquema general e identificación con el problema El esquema voraz se aplica a problema de optimización. Consiste en ir seleccionando elementos de un conjunto de candidatos que se van incorporando a la solución. Se caracterizan porque nunca se deshace una decisión ya tomada: los candidatos desechados no vuelven a ser considerados y los incorporados a la solución permanecen en ella hasta al final del algoritmo. Es crucial determinar la función de selección adecuada que nos asegure que la solución obtenida es óptima. Esta notación algorítmica puede escribirse así (libro de Brassard página 214): fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← elemento que maximiza objetivo (x) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun

Page 32: Examenes resueltos

Hemos de particularizar las siguientes funciones: • Solución (S): El número de cintas, que es n. • Objetivo (x): Función que devuelve la cinta con menor número de registros de entre el conjunto de

cintas disponibles. • Factible (x) (o completable): Esta función es siempre cierta, pues cualquier orden de combinación

es válido. Estructuras de datos Se utilizarán vectores de n valores naturales para representar los conjuntos. Por ejemplo, para el conjunto C se define la variable c como vector de naturales, siendo c[i] = ni la expresión de que la cinta i consta de ni registros. El conjunto S puede representarse de manera análoga. Para representar la ausencia de un elemento puede usarse cualquier marcador (por ejemplo, el valor ∅). Algoritmo completo a partir del refinamiento del esquema Adaptamos el algoritmo general a lo dicho anteriormente: fun voraz (c: vector) dev (s: vector) para i ← 0 hasta n hacer s[i] ← 0 fpara i ← 0 mientras i < n hacer x ← seleccionar (c) c[i] ← 0 s[i] ← x i ← i+1 fmientras dev S ffun Esta solución está modificada respecto de la solución aportada en el libro de problemas. Se han añadido una línea (la de i←i+1) y se ha modificado la línea c[i]←0. Con esto trato de decir, que no es seguro que esté correcta la respuesta, sólo que pienso que había algunas erratas. La única función (de selección) por desarrollar es aquella que obtiene en cada momento la cinta con menor número de registros de entre las cintas no usadas todavía y almacenadas en el vector de cintas. La función devuelve la cinta, pero no la elimina del conjunto de candidatos. Los argumentos sin c, vector de cintas y cinta que es un vector de ni registros. fun seleccionar (c: vector) dev cinta: vector min ← 1 para j ← 1 hasta n hacer si c[j] < c[min] entonces min ← j fsi fpara dev c[min] ffun Demostración de optimalidad La demostración corresponde con la de minimización del tiempo en el sistema, dada ya en ejercicios antes, por lo que evitamos escribirla de nuevo. Análisis del coste La función objetivo (para nosotros seleccionar) tiene coste de Ο(n) y el bucle principal (“mientras”) se repite n veces, por lo que el coste es Ο(n2).

Page 33: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero de 1997

Examen segunda semana

Queremos grabar n canciones de duraciones t1 : : : tn en una cinta de audio de

duracion T <P

n

i=1ti.

Problema 1(5 puntos). Dise~nar un algoritmo que permita almacenar el maximo

numero de canciones en el espacio disponible.

Problema 2(5 puntos). Dise~nar un algoritmo que seleccione las canciones de

forma que se minimice el espacio vaco que queda en la cinta.

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Vuelta atras: descripcion del arbol de busqueda asociado.

Page 34: Examenes resueltos
Page 35: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Septiembre de 1997

Original

Problema 1 (5 puntos). Una empresa de mensajera dispone de tres motoristas en distintospuntos de la ciudad, y tiene que atender a tres clientes en otros tres puntos. Se puede estimar eltiempo que tardara cada motorista en atender a cada uno de los clientes (en la tabla, en minutos):

Moto 1 Moto 2 Moto 3

cliente1 30 40 70

cliente2 60 20 10

cliente3 40 90 20

Dise~nar un algoritmo que distribuya un cliente a cada motorista de forma que se minimice elcoste total (en tiempo) de atender a los tres clientes.

Problema 2 (5 puntos). Sea un juego de tablero para dos personas, en el que se turnan paramover las piezas del tablero segun unas reglas determinadas. Daremos por conocidos:

Una estructura de datos jugada que nos da dos tipos de informacion: en un registro tablero,por un lado, la situacion de las chas en el tablero. Y en un registro turno, por otro lado,quien debe mover a continuacion (o, en caso de ser una posicion nal, quien es el ganador),con la siguiente convencion: 1 signica que le toca mover al jugador que comenzo. 2, alsegundo jugador. 3, que la partida acabo con triunfo del primer jugador, y 4, que la partidaacabo con triunfo del segundo jugador.

Una funcion

funcion movimientos (j: jugada) devolver l:lista de jugada

que da todas las jugadas posibles a partir de una dada.

Supondremos que en el juego no se pueden dar ciclos (volver a una situacion previa en el juego),que no se puede prolongar indenidamente y que la partida no puede acabar en tablas. Dise~narun algoritmo que averigue si existe una estrategia optima para el jugador que mueve primero, deforma que se asegure la victoria siguiendo esa estrategia. >Se puede aplicar el algoritmo, en teora,al juego del ajedrez? >Y en la practica?

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Exploracion en grafos: descripcion del arbol de busqueda asociado.

Page 36: Examenes resueltos
Page 37: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero de 1998

Primera Semana

Problema 1 (5 puntos). Se considera un juego solitario en el que el tablero se compone devarios huecos dispuestos en forma de cruz y un conjunto de bolas que, inicialmente, cubren todosellos excepto el hueco central (ver gura izquierda). Siempre que haya dos bolas y un hueco vacoconsecutivos, se puede saltar con la primera bola al hueco vaco, retirando la bola intermedia (verun posible primer movimiento en g. derecha). Solo se consideran movimientos horizontales overticales, nunca en diagonal. El objetivo del juego es eliminar progresivamente todas las bolasdel tablero hasta que solo quede una. Dise~nar un algoritmo que encuentre una solucion al juego.

Problema 2 (5 puntos). En la compleja red de metro de Japon, la cantidad que se paga porun billete es proporcional a la distancia que se recorre. Por tanto, es necesario instalar en cadaestacion un panel informativo que informe del precio del billete a cualquier otra estacion de la red.Describir un algoritmo que deduzca la informacion de todos esos paneles, basando el calculo en lasuposicion de que el viajero se trasladara de una estacion a otra por el camino mas corto.

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Breve descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos requeridas.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado entre los ejemplares del problema.

Exploracion en grafos: descripcion del grafo de busqueda asociado.

Page 38: Examenes resueltos
Page 39: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1998 (Primera Semana) Problema 1 (5 puntos). Se considera un juego solitario en el que el tablero se compone de varios huecos dispuestos en forma de cruz y un conjunto de bolas que, inicialmente, cubren todos ellos excepto el hueco central (ver figura izquierda). Siempre que haya dos bolas y un hueco vacío consecutivos, se puede saltar con la primera bola al hueco vacío, retirando la bola intermedia (ver un posible primer movimiento en fig. derecha). Sólo se consideran movimientos horizontales o verticales, nunca en diagonal. El objetivo del juego es eliminar progresivamente todas las bolas del tablero hasta que sólo quede una. Diseñar un algoritmo que encuentre una solución al juego. Solucionado por Vuelta atrás.

El tablero de juego se puede representar mediante una matriz 7*7 con tres valores posibles:

• 0 si la casilla está vacía. • 1 si la casilla tiene una pieza. • -1 si la casilla es no válida. Se utiliza para deshabilitar las posiciones de las esquinas, que no forman

parte del tablero.

La solución consiste en la secuencia de movimientos hasta llegar a la posición final. Es posible que una casilla del tablero sea visitada varias veces por distintas piezas a lo largo de una partida: no podemos utilizar un tablero para representar la solución Utilizaremos una secuencia X = (x1,…,xm), en la que xi representa el movimiento i -ésimo. Además, m = 31. Cada movimiento debe contener información para deshacerlo si es necesario:

• posición del tablero desde la que se mueve. • posición a la que se mueve. • posición de la _cha que se salta.

dX = (1, 0, -1, 0) ; dY = (0, 1, 0, -1) //constantes globales fun continental(D[1..7,1..7],sol[1..31],etapa) si esFin(D,etapa) entonces devolver cierto desde i ← 1 hasta 7 hacer desde j ← 1 hasta 7 hacer si D[i,j] = 1 entonces desde v ← 1 hasta 4 hacer si esValido(D,i,j,v) entonces sol[etapa].origen.x ← i ; sol[etapa].origen.y ← j sol[etapa].destino.x ← i+2*dX[v] ; sol[etapa].destino.y ← j+2*dY[v] sol[etapa].comido.x ← i+dX[v] ; sol[etapa].comido.y ← j+dY[v] hacerMovimiento(D,sol[etapa]) si continental(D,sol,etapa+1) entonces devolver cierto si no deshacerMovimiento(D,sol[etapa]) fin si fin desde fin si fin desde fin desde devolver falso fin fun

X X X X X X X X X X X X

X X X X X X X X X X X X X X X X X O X X X ===> X X X X X X X X X X X X X X X X X O X X X

X X X X O X X X X X X X

Page 40: Examenes resueltos

fun esFin(D,etapa) si etapa = 31 ^ D[4,4] = 1 entonces devolver cierto devolver falso fin fun fun esValido(D,i,j,v) // Ya se ha comprobado que D[i,j]=1 destX ← i+2*dX[v] ; destY ← j+2*dY[v] comX ← i+dX[v] ; comY ← j+dY[v] si 1 ≤ destX ≤ 7 ^ 1 ≤ destY ≤ 7^ D[destX,destY]=0 ^ D[comX,comY]=1 entonces devolver cierto si no devolver falso fin fun proc hacerMovimiento(D,mov) D[mov.origen.x,mov.origen.y] ← 0 D[mov.destino.x,mov.destino.y] ← 1 D[mov.comido.x,mov.comido.y] ← 0 fin proa proc deshacerMovimiento(D,sol[etapa]) D[mov.origen.x,mov.origen.y] ← 1 D[mov.destino.x,mov.destino.y] ← 0 D[mov.comido.x,mov.comido.y] ← 1 fin proa fun llamador continental(sol) crear D[1..7,1..7] D ← -1,-1, 1, 1, 1,-1,-1, -1,-1, 1, 1, 1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1,-1, 1, 1, 1,-1,-1, -1,-1, 1, 1, 1,-1,-1 devolver continental(D,sol,1) fin fun La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 41: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Febrero de 1998

Segunda Semana

Problema 1 (5 Puntos) Sobre un eje de coordenadas positivo se tienen representados ediciosen forma de rectangulos. Cada rectangulo descansa sobre el eje horizontal y se representa porsus abscisas inicial y nal y por su altura. La linea de horizonte es el contorno que forman losedicios. Se pide programar un algoritmo eciente que encuentre la linea de horizonte que formaun conjunto de edicios.

Ej. Una ciudad C = f(0; 4; 7); (2; 14; 4); (7; 12; 5); (8; 17; 2); (19; 21; 10)g tendra una linea dehorizonte H = f(0; 4; 7); (4; 7; 4); (7; 12; 5); (12; 14; 4); (14; 17; 2); (17; 19; 0); (19; 21; 10)g:

Problema 2 (5 Puntos) Se tiene un mecano de 8 piezas. Las piezas se acoplan entre s mediantetornillos, formando distintos juguetes dependiendo de como se combinen. Un juguete completo esaquel formado por las 8 piezas. El gasto de tornillos de cada acoplamiento es el indicado en lasiguiente tabla: (Un indica que las piezas no encajan)

p1 p2 p3 p4 p5 p6 p7 p8

p1 - 7 12 - 4 - - -

p2 7 - 2 6 1 - 1 -

p3 12 2 - 4 - 10 - 3

p4 - 6 4 - - 3 2 -

p5 4 1 - - - 20 10 -

p6 - - 10 3 20 - 5 -

p7 - 1 - 2 10 5 - -

p8 - - 3 - - - - -

Se pide construir un algoritmo que calcule la combinacion de piezas que forman un juguetecompleto minimizando el gasto de tornillos.

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Breve descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos requeridas.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado entre los ejemplares del problema.

Exploracion en grafos: descripcion del grafo de busqueda asociado.

Page 42: Examenes resueltos
Page 43: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1998 (Segunda Semana) Problema 1 (5 puntos). Sobre un eje de coordenadas positivo se tienen representados edificios en forma de rectángulos. Cada rectángulo descansa sobre el eje horizontal y se representa por sus abscisas inicial y final y por su altura. La línea de horizonte es el contorno que forman los edificios. Se pide programar un algoritmo eficiente que encuentre la línea de horizonte que forma un conjunto de edificios. Ej. Una ciudad C = (0; 4; 7); (2; 14; 4); (7; 12; 5); (8; 17; 2); (19; 21; 10) tendrá una línea de horizonte H = (0; 4; 7); (4; 7; 4); (7; 12; 5); (12; 14; 4); (14; 17; 2); (17; 19; 0); (19; 21; 10): Problema 2 (5 puntos). Se tiene un mecano de 8 piezas. Las piezas se acoplan entre sí mediante tornillos, formando distintos juguetes dependiendo de cómo se combinen. Un juguete completo es aquel formado por las 8 piezas. El gasto de tornillos de cada acoplamiento es el indicado en la siguiente tabla: (Un - indica que las piezas no encajan)

Se pide construir un algoritmo que calcule la combinación de piezas que forman un juguete completo minimizando el gasto de tornillos. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø

Page 44: Examenes resueltos

Indicar que estructuras de datos son necesarias. nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; filas_no_asignadas: lista de cardinal; coste: cardinal; Montículo de mínimos (cota mejor la de menor coste) Desarrollar el algoritmo completo. Las funciones generales del esquema general que hay que instanciar son: 1. a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) 2. b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” 3. c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores posibles para asignaciones[último_asignado+1]) 4. Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0; nodo.coste=0; cota:=acotar(nodo,costes); poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras

devolver ∅; Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer minimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota; Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista;

Page 45: Examenes resueltos

Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 46: Examenes resueltos
Page 47: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Septiembre de 1998

Original

Problema 1 (5 puntos). Dado un conjunto de n rectangulos cuyos lados son paralelos

a los ejes del plano, hallar el rectangulo interseccion de todos los rectangulos mediante un

algoritmo eciente.

Problema 2 (5 puntos). Una cadena euleriana en un grafo no orientado es una cadena

que une cada arista del grafo exactamente una vez. Escribir un algoritmo que decida si un

grafo dado tiene una cadena euleriana y, si es as, que devuelva esa cadena.

La resolucion de cada problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Breve descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos requeridas.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado entre los ejemplares del problema.

Exploracion en grafos: descripcion del grafo de busqueda asociado.

Page 48: Examenes resueltos
Page 49: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 1999 – Primera Semana Problema 1 (5 puntos). La nave Mir tiene que reensamblar sus paneles modulares debido a una sobrecarga. Hay 6 paneles que se ensamblan unos con otros formando una estructura única y de la combinación de ensamblaje depende el gasto de energía. La tabla adjunta muestra el coste en amperios de cada unión:

P1 P2 P3 P4 P5 P6 P1 5 9 4 2 1 1 P2 6 0 1 1 3 5 P3 1 9 5 5 2 5 P4 1 4 2 3 5 6 P5 3 6 7 7 1 3 P6 1 3 5 6 2 8

Se pide diseñar un algoritmo que forme una estructura con todos los módulos minimizando el coste total tanto de uniones como del coste de las mismas. Problema 2 (5 puntos). Dado un mapa político de países, diseñar un algoritmo que coloree con 3 colores los países de manera que 2 países fronterizos no tengan el mismo color. ¿Tiene este problema solución en todos los casos? Pon ejemplos si los hay. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 50: Examenes resueltos
Page 51: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1999 (Primera Semana) Problema 1 (5 puntos). La nave Mir tiene que reensamblar sus paneles modulares debido a una sobrecarga. Hay 6 paneles que se ensamblan unos con otros formando una estructura única y de la combinación de ensamblaje depende el gasto de energía. La tabla adjunta muestra el coste en amperios de cada unión:

P1 P2 P3 P4 P5 P6 P1 5 9 4 2 1 1 P2 6 0 1 1 3 5 P3 1 9 5 5 2 5 P4 1 4 2 3 5 6 P5 3 6 7 7 1 3 P6 1 3 5 6 2 8

Se pide diseñar un algoritmo que forme una estructura con todos los módulos minimizando el coste total tanto de uniones como del coste de las mismas. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias. nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; filas_no_asignadas: lista de cardinal; coste: cardinal; Montículo de mínimos (cota mejor la de menor coste)

Page 52: Examenes resueltos

Desarrollar el algoritmo completo. Las funciones generales del esquema general que hay que instanciar son: 1. a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) 2. b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” 3. c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores posibles para asignaciones[último_asignado+1]) 4. Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0; nodo.coste=0; cota:=acotar(nodo,costes); poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras

devolver ∅; Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer minimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota; Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista; Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 53: Examenes resueltos

Problema 2 (5 puntos). Dado un mapa político de países, diseñar un algoritmo que coloree con 3 colores los países de manera que 2 países fronterizos no tengan el mismo color. ¿Tiene este problema solución en todos los casos? Pon ejemplos si los hay. Solución: (Resuelto en TÉCNICAS DE DISEÑO DE ALGORITMOS Pág. 246) Es un problema de búsqueda no de optimización por lo tanto descarto los esquemas voraces y de ramificación y poda, tampoco se puede obtener una solución dividiendo el problema en subproblemas más pequeños, también descarto el esquema de divide y vencerás. El esquema que elijo es el de vuelta atrás. Para resolverlo se utilizan grafos puesto que un mapa puede ser representado por un grafo conexo. Cada vértice corresponde a un país y cada arco entre dos vértices indica que los dos países son vecinos. Desde el siglo XVII ya se conoce que con cuatro colores basta para colorear cualquier mapa planar, pero sin embargo existen situaciones en donde no nos importa el número de colores que se utilicen. Para implementar un algoritmo de Vuelta Atrás, la solución al problema puede expresarse como una n-tupla de valores X = [x1, x2, ..., xn] donde xi representa el color del i-ésimo vértice. El algoritmo que resuelve el problema trabajará por etapas, asignando en cada etapa k un color (entre 1 y m) al vértice k-ésimo. En primer lugar, y para un grafo con n vértices y con m colores, el algoritmo que encuentra una solución al problema es el siguiente: Esquema General:

fun vuelta - atras(ensayo)si valido (ensayo) es una solucion entonces dev (ensayo)si no para cada hijo compleciones (ensayo)

si condiciones de poda (hijo) hacer v∈

uelta - atras(hijo) fsifpara

fsiffun

Desarrollar el algoritmo completo. CONST n = ...; (* numero de vertices *) m = ...; (* numero maximo de colores *) TYPE GRAFO=ARRAY[1..n],[1..n]OF BOOLEAN; (* matriz adyacencia *) SOLUCION = ARRAY [1..n] OF CARDINAL; VAR g:GRAFO; X:SOLUCION; exito:BOOLEAN PROCEDURE Colorear1(k:CARDINAL); (* busca una posible solucion *) BEGIN X[k]:=0; REPEAT INC(X[k]); IF Aceptable(k) THEN IF k<n THEN Colorear1(k+1) ELSE exito:=TRUE END END UNTIL (exito) OR (X[k]=m) END Colorear1;

Page 54: Examenes resueltos

La función Aceptable es la que comprueba las restricciones definidas para este problema, que consiste en que dos países vecinos (vértices adyacentes) no pueden tener el mismo color: PROCEDURE Aceptable(k: CARDINAL): BOOLEAN; VAR j: CARDINAL; BEGIN FOR j:=1 TO k-1 DO IF (g[k,j]) AND (X[k]=X[j]) THEN RETURN FALSE END END; RETURN TRUE END Aceptable; El programa principal del algoritmo ha de invocar a la función Colorear1 como sigue: ... exito:=FALSE; Colorear1(1); IF exito THEN ComunicarSolucion(X) ... Supongamos ahora que lo que deseamos es obtener todas las formas distintas de colorear un grafo. Entonces el algoritmo anterior podría ser modificado de la siguiente manera: PROCEDURE Colorear2(k:CARDINAL); (* busca todas las soluciones *) BEGIN X[k]:=0; REPEAT INC(X[k]); IF Aceptable(k) THEN IF k<n THEN Colorear2(k+1) ELSE ComunicarSolucion(X) END END UNTIL (X[k]=m) END Colorear2;

Page 55: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 1999 – Segunda Semana Problema 1 (5 puntos). Diseñar un algoritmo que tome un mapa político y coloree el mapa con el mínimo número de colores posible de manera que dos países fronterizos no tengan el mismo color. Problema 2 (5 puntos). Una liga de n equipos ei juega a un juego donde solo se pierde o se gana, pero no se empata. Diseñar un algoritmo que realice una pseudo-ordenación (e1,e2 . - - ,en) a partir de la tabla de resultados de lo equipos de manera que e1 haya ganado a e2, e2 a e3, etc. El coste debe ser a lo sumo O(nlogn) La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 56: Examenes resueltos
Page 57: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 1999 (Segunda Semana) Problema 1 (5 puntos). Diseñar un algoritmo que tome un mapa político y coloree el mapa con el mínimo número de colores posible de manera que dos países fronterizos no tengan el mismo color. Solución: (Resuelto en TÉCNICAS DE DISEÑO DE ALGORITMOS Pág. 247) Es un problema de búsqueda no de optimización por lo tanto descarto los esquemas voraces y de ramificación y poda, tampoco se puede obtener una solución dividiendo el problema en subproblemas más pequeños, también descarto el esquema de divide y vencerás. El esquema que elijo es el de vuelta atrás. Para resolverlo se utilizan grafos puesto que un mapa puede ser representado por un grafo conexo. Cada vértice corresponde a un país y cada arco entre dos vértices indica que los dos países son vecinos. Desde el siglo XVII ya se conoce que con cuatro colores basta para colorear cualquier mapa planar, pero sin embargo existen situaciones en donde no nos importa el número de colores que se utilicen. Para implementar un algoritmo de Vuelta Atrás, la solución al problema puede expresarse como una n-tupla de valores X = [x1, x2, ..., xn] donde xi representa el color del i-ésimo vértice. El algoritmo que resuelve el problema trabajará por etapas, asignando en cada etapa k un color (entre 1 y m) al vértice k-ésimo. En primer lugar, y para un grafo con n vértices y con m colores, el algoritmo que encuentra una solución al problema es el siguiente: Esquema General:

fun vuelta - atras(ensayo)si valido (ensayo) es una solucion entonces dev (ensayo)si no para cada hijo compleciones (ensayo)

si condiciones de poda (hijo) hacer v∈

uelta - atras(hijo) fsifpara

fsiffun

Desarrollar el algoritmo completo. CONST n = ...; (* numero de vertices *) m = ...; (* numero maximo de colores *) TYPE GRAFO=ARRAY[1..n],[1..n]OF BOOLEAN; (* matriz adyacencia *) SOLUCION = ARRAY [1..n] OF CARDINAL; VAR g:GRAFO; X:SOLUCION; exito:BOOLEAN PROCEDURE Colorear3(k:CARDINAL); (* busca la solucion optima *) VAR numcolores:CARDINAL; BEGIN X[k]:=0; REPEAT INC(X[k]); IF Aceptable(k) THEN IF k<n THEN Colorear3(k+1) ELSE numcolores:=NumeroColores(X); IF minimo>numcolores THEN mejor:=X; minimo:=numcolores END END END UNTIL (X[k]=m) END Colorear3;

Page 58: Examenes resueltos

La función NumeroColores es la que calcula el número de colores utilizado en una solución. Por la forma en la que hemos ido construyendo las soluciones no queda garantizado que los colores utilizados posean números consecutivos, de forma que es necesario comprobar todos los colores para saber cuales han sido usados en una solución concreta: PROCEDURE NumeroColores(X:SOLUCION):CARDINAL; VAR i,j,suma:CARDINAL; sigo:BOOLEAN; BEGIN suma:=0; FOR j:=1 TO m DO (* recorremos todos los colores *) i:=1; sigo:=FALSE; WHILE (i<n) AND sigo DO IF X[i]=j THEN (* encontrado el color j *) INC(suma); sigo:=FALSE END END END; RETURN suma; END NumeroColores; En estos algoritmos es importante hacer notar que la constante m que indica el número máximo de colores a utilizar ha de ser mayor o igual a cuatro, pues se sabe que con cuatro colores basta siempre que el grafo corresponda a un mapa. Ahora bien, conviene también observar que no todo grafo conexo representa a un mapa planar; por ejemplo un grafo de cinco vértices completamente conexo, es decir, que tenga todos sus vértices conectados entre sí, no puede corresponder a un mapa en el plano. Problema 2 (5 puntos). Una liga de n equipos ei juega a un juego donde solo se pierde o se gana, pero no se empata. Diseñar un algoritmo que realice una pseudo-ordenación (e1,e2 . - - ,en) a partir de la tabla de resultados de lo equipos de manera que e1 haya ganado a e2, e2 a e3, etc. El coste debe ser a lo sumo O(nlogn)

Page 59: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2000 Primera Semana Cuestión 1 (2 puntos). Comparar la eficiencia de los algoritmos de ordenación Quicksort (ordenación rápida) y Mergesort (ordenación por fusión). Cuestión 2 (1 puntos). Comenta las condiciones de poda que has utilizado en la realización de la práctica del Nim. Cuestión 3 (2 puntos). ¿Que variante del problema de la mochila admite una solución voraz y ¿por qué? ¿Qué variante no admite solución voraz? Poner un ejemplo del segundo caso en el que la solución voraz no nos lleve a la solución óptima. PROBLEMA (5 puntos). Se considera un juego de tablero genérico con las siguientes características: - Juegan dos oponentes entre sí. Cada jugador mueve alternativamente. El juego acaba con la victoria de uno de los dos jugadores, o en tablas. - Se supone conocido: - Una estructura de datos situación que nos da la situación actual del juego: qué jugador tiene el turno, disposición de las fichas en el tablero, etc. - Una función funcion movimientos(j: situacion) devolver l:lista de situación que nos da todas las jugadas posibles a partir de una dada. Aceptaremos que, si nos devuelve una lista vacía, es porque el juego ha terminado. Se pide diseñar un algoritmo que encuentre cuál es el número de movimientos de la (o las) partidas más cortas. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 60: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2000 (Primera Semana) Cuestión 1. Comparar la eficiencia de los algoritmos de ordenación Quicsort (ordenación rápida) y Mergesort (ordenación por fusión). (Respuesta: Fundamentos de Algoritmia, pag. 260). El algoritmo Quicksort emplea un tiempo promedio de nlogn, en el peor caso de n2. El algoritmo por fusión mergesort utiliza un tiempo de nlogn (siempre observando la precaución de equilibrar los subcasos a tratar). Pese a esto, en la práctica Quicksort es más rápido en un tiempo c constante. Además el algoritmo mergesort requiere de un espacio extra para tratar los distintos casos sin perder eficiencia (hacer la ordenación in situ lleva asociado un incremento de la constante oculta bastante alto). Cuestión 2. Comenta las condiciones de poda que has utilizado en la realización de la práctica del Nim. Cuestión 3.¿Qué variante del problema de la mochila admite solución voraz, y porqué?¿Qué variante no admite solución voraz? Poner un ejemplo del segundo caso en el que la solución voraz no nos lleve a la solución óptima. (Respuesta: Fundamentos de algoritmia, pag 227, contraejemplo en pag. 300). La variante del problema de la mochila que admite solución voraz es la variante continua, donde podemos fragmentar los objetos. Esta variante admite solución voraz porque encontramos una función de selección que nos permite escoger del candidato a cada paso de forma que obtengamos una solución óptima. Dicha función consiste en escoger los objetos por orden decreciente (de mayor a menor) según su relación valor/peso, lo que nos lleva a una solución óptima. La variante que no admite solución optima es la que no nos permite fragmentar los objetos, veamos esto con un ejemplo. Dada la siguiente relación de objetos valor-peso para una mochila de capacidad 10 (W=10 , peso máximo de la mochila) . a b c

iw 6 5 5

iv 8 5 5 Según el algoritmo voraz de la variante continua tomaríamos los objetos según su orden decreciente en función de la relación valor/peso. De este modo tendríamos: a (vi/wi = 1,333) , b (vi/wi= 1) y c(vi/wi=1) . La sucesión a, b y c. Sin embargo como en esta ocasión no podemos fragmentar los objetos al introducir en la mochila el objeto a de peso 6 ya no podemos introducir ninguno más, el valor conseguido será entonces de 6; mientras que si introducimos primero el objeto b, queda aún espacio para el objeto c, con lo que en esta ocasión hemos utilizado el peso total máximo de la mochila y el valor conseguido es de 10. Siendo esta la solución óptima. Vemos con este ejemplo como el criterio seguido en la variante continua del problema no puede aplicarse en el caso en el que los objetos no puedan fragmentarse.

Page 61: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2000 – Segunda semana Cuestión 1 (1 puntos). Poner algún ejemplo en el que un enfoque de Divide y Vencerás nos lleve a un coste exponencial de forma innecesaria. Cuestión 2 (2 puntos). ¿Puedes explicar brevemente que papel desempeña un montículo en el algoritmo de Ramificación y Poda? ¿Cuál es el criterio general para realizar la poda en este algoritmo?. Cuestión 3 (2 puntos). En una exploración de un árbol de juego con dos oponentes a nivel de profundidad 4 (contando la raíz como nivel 1) y siguiendo la estrategia del MINIMAX nos encontramos con la siguiente puntuación:

[[[-7,5] [-3] [-10,-20,0]] [[-5,-10] [-15,20]] [[1] [6,-8,14] [-30,0] [-8,-9]]] donde los corchetes indican agrupación de nodos por nodo padre común. Se pide propagar las puntuaciones y elegir la rama más adecuada a partir de la raíz sabiendo que el nodo raíz corresponde al jugador A, a mayor valor, mejor jugada para A, y que se alternan para mover. ¿En que se diferencia esta estrategia de juego de la utilizada para resolver la práctica?. Problema (5 Puntos). La Base Aérea de Gando (Gran Canaria) posee una flota variada de n cazas de combate ci (con i ∈ 1..n). Cada caza tiene que salir del bunker y superar un tiempo de rodadura ki más un tiempo de despegue ti para estar en el aire y operativo. Durante este proceso la nave es vulnerable. Suponiendo que se produce un ataque sorpresa, construir un algoritmo que averigüe el orden de despegue de las aeronaves de manera que se minimice el tiempo medio durante el cual son vulnerables. Supongamos ahora que cada aeronave ci posee un índice acumulativo bi de importancia estratégica siempre que despegue antes de la ranura temporal hi

(con i ∈ 1..n). Si queremos maximizar la importancia estratégica una vez que hayan despegado todas ¿Qué tipo de problema es éste? ¿Con que esquema se resuelve?. Explica en un párrafo breve el funcionamiento del algoritmo. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 62: Examenes resueltos
Page 63: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2000 (Segunda Semana) Cuestión 1.Poner algún ejemplo en el que un enfoque divide y vencerás nos lleve a un coste exponencial de forma innecesaria. (Respuesta: Fundamentos de Algoritmia, pag.83). Un ejemplo claro de esto es utilizar la definición recursiva de la función de Fibonacci sin más, de este modo el siguiente algoritmo conlleva un coste exponencial, existiendo formas de obtener la solución en un coste inferior utilizando un enfoque distinto al de divide y vencerás.

Fun Fib(n)si (n < 2) entonces devolver n

sinoDevolver Fib(n -1) + Fib(n - 2)

FsiFfun

Cuestión 2.¿Puedes explicar brevemente qué papel desempeña un montículo en el algoritmo de ramificación y poda? ¿Cuál es el criterio general para realizar la poda en este algoritmo? (Respuesta Fundamentos de Algoritmia, pag. 354, y 348). El montículo es la forma ideal de mantener la lista de nodos que han sido generados pero no explorados en su totalidad en los diferentes niveles del árbol, tomando como valor el de la función de cota. De este modo tendremos ordenados los nodos según la cota, de manera que el elemento en la cima será el más factible de ser explorado a continuación. El criterio consiste en calcular una cota del posible valor de aquellas soluciones que el grafo pudiera tomar más adelante, si la cota muestra que cualquiera de estas soluciones será necesariamente peor que la mejor solución hallada hasta el momento entonces no seguimos explorando esa parte del grafo. Cuestión 3.En una exploración de un árbol de juego con dos oponentes a nivel de profundidad 4 (Contando la raiz como nivel 1) y siguiendo la estrategia MINIMAX nos encontramos con la siguiente puntuación: [[[-7,5][-3][-10,-20,0]] [[-5,-10][-15,20]] [[1] [6,-8,14] [-30,0] [-8,-9]]] Donde los corchetes indican agrupación de nodos por nodo padre común. Se pide propagar las puntuaciones y elegir la rama más adecuada a partir de la raíz sabiendo que el nodo raíz corresponde al jugador A, a mayor valor, mejor jugada para A, y que se alternan en mover. ¿En que se diferencia esta estrategia de juego de la utilizada para resolver la práctica? (Alg. Minimax pag. 354) El nodo raíz corresponde al jugador A, el nodo 2 a B, el nodo 3 a A y consecuentemente el nodo 4 a B, según lo cual los valores corresponderán por tanto a una jugada de B. Como anteriormente juega A, y los mejores valores para A son los mayores, cogerá por tanto los mayores valores de las jugadas posibles. Cuando juegue B es lógico que este tomará aquellas jugadas que sean peores para A, luego cogerá los valores más pequeños.

Page 64: Examenes resueltos

Problema (5 Puntos). La Base Aérea de Gando (Gran Canaria) posee una flota variada de n cazas de combate ci (con i ∈ 1..n). Cada caza tiene que salir del bunker y superar un tiempo de rodadura ki más un tiempo de despegue ti para estar en el aire y operativo. Durante este proceso la nave es vulnerable. Suponiendo que se produce un ataque sorpresa, construir un algoritmo que averigüe el orden de despegue de las aeronaves de manera que se minimice el tiempo medio durante el cual son vulnerables. Supongamos ahora que cada aeronave ci posee un índice acumulativo bi de importancia estratégica siempre que despegue antes de la ranura temporal hi

(con i ∈ 1..n). Si queremos maximizar la importancia estratégica una vez que hayan despegado todas ¿Qué tipo de problema es éste? ¿Con que esquema se resuelve?. Explica en un párrafo breve el funcionamiento del algoritmo. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias.

Montículo de mínimos (cota mejor la de menor coste)

El algoritmo es el siguiente: (minimizar el tiempo medio)

tipos nodo = reg sol[1..n]de 1..n k:0..n tiempo:real tiempo-opt:real prioridad asignado[1..n]de bool freg ftipos

fun pre-calculo-estimaciones (T[1..n, 1..n] de real) dev (opt[0..n], pes[0..n] de real) var rapido[1..n], lento[1..n] de real calculo de los minimos y maximos por filas para i = 1 hasta n hacer rapido[i]:= T[i,1] lento[i]:= T[i,1] para j = 2 hasta n hacer rapido[i]:= min(rapido[i],T[i,j]) lento[i]:= max(lento[i],T[i,j]) fpara fpara calculo de las estimaciones opt[n]:= 0; pes[n]:= 0; para i = n-1 hasta 0 paso -1 hacer opt[i]:= opt[i+1]+ rapido[i+1] pes[i]:= pes[i+1]+ lento[i+1] fpara ffun

Page 65: Examenes resueltos

El algoritmo es el siguiente: (maximizar la importancia estratégica)

fun base-rp(T[1..n,1..n]de real)dev (sol-mejor[1..n]de 1..n, tiempo-mejor:real) var X,Y: nodo,C:colapr[nodo],opt[0..n],pes[0..n]de real (opt,pes):= pre-calculo-estimaciones(T) generamos la Raíz Y.k:=0; Y.asignado[1..n]=[falso]; Y.tiempo:=0; Y. tiempo-opt:=opt[0] C:= cp-vacia(); añadir(C,Y) tiempo-mejor:= pes[0] mientras ¬es-cp-vacia?(C)^(minimo(C).tiempo-opt ≤ tiempo-mejor) hacer Y:= minimo (C); eliminar-min(C) generamos los hijos de Y X.k:=Y.k+1; X.sol:=Y.sol; X.asignado:=Y.asignado para t=1 hasta n hacer si ¬ X.asignado[t] entonces X.sol[X.k]:=t; X.asignado[t]:= cierto X.tiempo:= Y.tiempo + T[X.k,t] X.tiempo-opt:= Y.tiempo + opt[X.k] si X.tiempo-opt ≤ tiempo-mejor entonces si X.k = n entonces sol-mejor:=X.sol; tiempo-mejor:= X.tiempo sino añadir(C,X) tiempo-mejor:= min(tiempo-mejor, X.tiempo + pes[X.k]) fsi fsi X.asigando[t]:= falso fsi fpara fmientras ffun

tipos nodo = reg sol[1..n]de 1..n k:0..n eficacia:real eficacia-opt:real prioridad asignado[1..n]de bool freg ftipos

fun base-max-rp(E[1..n,1..n]de real)dev (sol-mejor[1..n]de 1..n, eficacia-mejor:real) var X,Y: nodo,C:colapr[nodo],opt[0..n],pes[0..n]de real (pes, opt):= pre-calculo-estimaciones(E) generamos la Raíz Y.k:=0; Y.asignado[1..n]=[falso]; Y.eficacia:=0; Y.eficacia -opt:=opt[0] C:= cp-vacia(); añadir(C,Y) eficacia-mejor:= pes[0] mientras ¬es-cp-vacia?(C)^ maximo(C).eficacia-opt ≤ eficacia-mejor hacer Y:= maximo (C); eliminar-max(C) generamos los hijos de Y X.k:=Y.k+1; X.sol:=Y.sol; X.asignado:=Y.asignado para t=1 hasta n hacer si ¬ X.asignado[t] entonces X.sol[X.k]:=t; X.asignado[t]:= cierto X.eficacia:= Y.eficacia + T[X.k,t] X.eficacia -opt:= Y.eficacia + opt[X.k] si X.eficacia -opt ≤ eficacia-mejor entonces si X.k = n entonces sol-mejor:=X.sol; eficacia-mejor:= X.eficacia sino añadir(C,X) eficacia-mejor:= min(eficacia-mejor, X. eficacia+ pes[X.k]) fsi fsi X.asigando[t]:= falso fsi fpara fmientras ffun

Page 66: Examenes resueltos

Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 67: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Septiembre 2.000 - Original

Cuestion 1. (1 punto). A la hora de hacer una exploracion ciega en ungrafo, >que criterios nos pueden decidir por una busqueda en profundidad oen anchura?

Cuestion 2 (2 puntos). La sucesion de Fibonacci se dene como fib(0) =fib(1) = 1; fib(n) = fib(n1)+fib(n2)si n 2. Que ocurre si aplicamosuna estrategia divide y venceras para calcular fib(n) usando directamentela denicion? >Que otras opciones existen? (2 puntos).

Cuestion 3 (2 puntos). >Cual es la relacion entre la ordenacion porseleccion y la ordenacion por montculo? >Como se re eja en la ecienciade los dos algoritmos? (2 puntos).

Problema (5 puntos). Sea T [1 : : : n] un vector de n elementos. La unicacomparacion que se permite entre esos elementos es el test de igualdad.Llamemos elemento mayoritario de T , si existe, a aquel que aparece estric-tamente mas de n=2 veces en T . Dise~nar un algoritmo que encuentre elelemento mayoritario de un vector (si existe) en un tiempo que sea, a losumo, O(n logn). Sugerencia: el elemento mayoritario de un vector debeserlo tambien, al menos, de una de sus dos mitades.

La resolucion del problema debe incluir, por este orden:

1. Eleccion razonada del esquema algortmico.

2. Descripcion del esquema usado e identicacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del renamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especicar, ademas:

Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado.

Exploracion en grafos: descripcion del arbol de busqueda asociado.

Page 68: Examenes resueltos
Page 69: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2000 Cuestión 1.A la hora de hacer una exploración ciega en un grafo ¿qué criterios nos pueden decidir por una búsqueda en profundidad o en anchura? (Respuesta: Fundamentos de Algoritmia, pag 340). A la hora de escoger un criterio u otro fundamentaremos nuestra decisión según el problema en cuestión y el tamaño del grafo generado. Si el problema consiste en encontrar el camino más corto desde un punto del grafo hasta otro, la exploración en anchura es la más adecuada. Del mismo modo, si el grafo a tratar es de un tamaño muy grande, de forma que no resulte manejable, o infinito, utilizaremos la exploración en anchura para realizar una exploración parcial de dicho grafo. En otro caso nos decidiremos por la exploración en profundidad. Cuestión 2.La sucesión de fibonacci se define como Fib(1)=1; fib(n)=fib(n-1)+fib(n-1) si n >= 2 ¿Qué ocurre si aplicamos una estrategia divide y vencerás para calcular fib(n) usando directamente la definición?¿Qué otras opciones existen?. (Respuesta. Fundamentos de Algoritmia pag. 83). Si utilizamos directamente la definición obtendremos un algoritmo con un coste exponencial. Dicho algoritmo sería el siguiente:

Fun Fibrec(n)si (n < 2) entonces devolver n

sinodevolver Fibrec(n -1) + Fibrec(n - 2)

FsiFfun

1; 0; 1

; ; ;

Fun Fibiter(n)i jpara k hasta n hacer

j j ii j i

Fparadevolver j

Ffun

← ←←← +← −

Y el principal problema es que calcularía varias veces los mismos valores, para evitar esto existe otra opción dada por el algoritmo iterativo, que requiere de un tiempo de orden n. Implementación en java de los dos algoritmos, con los tiempos de ejecución: import java.io.*; public class fibrec public static long fib(int n) if (n <= 1) return n; else return fib(n-1) + fib(n-2); public static void main(String[] args) throws IOException System.out.print("numero: "); BufferedReader b=new BufferedReader (new InputStreamReader (System.in)); String numero2 =b.readLine (); int N=Integer.parseInt (numero2); double timeInicial = System.currentTimeMillis(); for (int i = 1; i <= N; i++) System.out.print(i + ": " + fib(i)); double timeFinal = System.currentTimeMillis(); System.out.println ("\tTiempo: "+(timeFinal-timeInicial)/1000 + " s.");

Page 70: Examenes resueltos

import java.io.*; public class fibiter public static void main(String[] args) throws IOException System.out.print("numero: "); BufferedReader b=new BufferedReader (new InputStreamReader (System.in)); String numero2 =b.readLine (); double N=Double.parseDouble (numero2); double f = 0, g = 1; double timeInicial = System.currentTimeMillis(); for (int i = 1; i <= N; i++) f = f + g; g = f - g; System.out.print(i+": "+f); double timeFinal = System.currentTimeMillis(); System.out.println("\tTiempo: "+(timeFinal-timeInicial)/1000 + " s."); Existe una tercera opción con la que tendríamos un algoritmo de fibonacci de orden ( )O logn Cuestión 3.¿Cuál es la relación entre la ordenación por selección y la ordenación por montículo? ¿Cómo se refleja en la eficiencia de los dos algoritmos? ORDENACIÓN POR SELECCIÓN: (página 121) La ordenación se hace sobre un array, seleccionando el menor elemento del array [ ] [ ]v 0 ..v n e

intercambiándolo con [ ]v 0 , luego el menor elemento del array [ ] [ ]1v ..v n y se intercambia con [ ]1v ,

así sucesivamente hasta llegar al elemento [ ]1v n − , de esta manera se obtiene el array ordenado ascendentemente La ordenación por selección requiere un tiempo que está en ( )2nΟ

fibiter 1: 1.0 Tiempo: 0.0 s. 2: 1.0 Tiempo: 0.0 s. 3: 2.0 Tiempo: 0.0 s. 4: 3.0 Tiempo: 0.0 s. 5: 5.0 Tiempo: 0.0 s. . . . 1456: 8.64010861026715E303 Tiempo: 0.266 s. 1457: 1.3979989397902865E304 Tiempo: 0.266 s. 1458: 2.2620098008170014E304 Tiempo: 0.266 s. 1459: 3.660008740607288E304 Tiempo: 0.266 s. 1460: 5.922018541424289E304 Tiempo: 0.266 s.

fun fibo (n:nat) dev f:nat si n ≤ 1 entonces f := n sino (a,b):= potF(n-1) f := a+b fsi ffun

fun potF (n:nat) dev (a,b:nat) casos n=0 → (a,b):= (1,0) n=1 → (a,b):= (0,1) n>1 ^ par (n) → (a,b):= potF(ndiv2) (a,b):= (a*a+b*b, a*b+b*(a+b)) n<1 ^ impar (n) → (a,b):= potF(ndiv2) (a,b):= (b*a+(a+b)*b, b*b+(a+b)*(a+b))) fcasos ffun

fibrec 1: 1 Tiempo: 0.0 s. 2: 1 Tiempo: 0.0 s. 3: 2 Tiempo: 0.0 s. 4: 3 Tiempo: 0.0 s. 5: 5 Tiempo: 0.0 s. . . 33: 3524578 Tiempo: 0.266 s. 34: 5702887 Tiempo: 0.422 s. 35: 9227465 Tiempo: 0.672 s. 36: 14930352 Tiempo: 1.094 s. 37: 24157817 Tiempo: 1.766 s. 38: 39088169 Tiempo: 2.844 s. 39: 63245986 Tiempo: 4.625 s. 40: 102334155 Tiempo: 7.485 s. 41: 165580141 Tiempo: 12.11 s. 42: 267914296 Tiempo: 19.61 s. 55: 139583862445 Tiempo: 11211.5 s. 56: 225851433717 Tiempo: 18116.5 s. 57: 365435296162 Tiempo: 29307.125 s. 58: 591286729879 Tiempo: 47427.625 s. 59: 956722026041 Tiempo: 76710.469 s.

Page 71: Examenes resueltos

ORDENACIÓN POR MONTÍCULO: (página 188) El montículo organiza sus datos como un árbol que es la única estructura que proporciona cotas de tiempo logarítmico. El montículo requiere un tiempo que está en ( )logn nΟ para ordenar n elementos. Es una variante del método de ordenación por selección, donde la búsqueda del elemento mínimo de un array se realiza mediante técnicas basadas en la construcción del montículo. Se cumple que para un nodo que ocupa la posición i del array, su hijo izquierdo ocupa la posición 2i , y su hijo derecho la posición 2i+1 Problema (5 puntos). Sea T[1..n] un vector de n elementos. La única comparación que se permite entre esos elementos es el test de igualdad. Llamemos elemento mayoritario de T, si existe, a aquel que aparece estrictamente más de n/2 veces en T. Diseñar un algoritmo que encuentre el elemento mayoritario de un vector (si existe) en un tiempo que sea, a lo sumo, O(nlogn). Sugerencia: el elemento mayoritario de un vector debe serlo también, al menos, de una de sus dos mitades. 1. Elección razonada del esquema algorítmico No es un problema de optimización, por lo tanto descarto el esquema voraz y ramificación y poda, como nos piden que el coste sea logarítmico y el problema se puede dividir en subproblemas más pequeños utilizaré el esquema de divide y vencerás. ESQUEMA GENÉRICO. función divide y vencerás (problema) si suficientemente simple (problema) entonces devolver solución simple (problema) sino hacer p1 … pk ← descomponer (problema)

para cada pi hacer si ← divide_y_vencerás (pi) fpara

devolver combinación (s1, ..., sk) fsi ffunción

Si el vector tiene un elemento mayoritario, este tiene que ser mayoritario en al menos una de las mitades del vector. Utilizando esta idea, podemos mirar de forma recursiva si existe un elemento mayoritario en cada una de las dos mitades del vector y si aparece en más de la mitad de las posiciones, será el elemento mayoritario buscado. El algoritmo que busca el mayoritario de [ ]..V c f es el siguiente:

[ ]( )[ ]

( )( )1 1

fun mayoritario V 1..n de elemento, c, f : nat dev existe : bool, mayor : elemento

si c = f entonces existe, mayor := cierto, V c

sino m := c+ f div2

existe , mayor := mayoritario V,c,m

( )

( )

2 2

1

1 1

existe , mayor := mayoritario V,m+1, f existe := falso si existe entonces comprobamos el primer candidato

existe, mayor := comprobar V,mayor ,c, f ,mayor

fsi

( )2

2 2

si ¬existe existe entonces comprobamos el segundo candidato

existe, mayor := comprobar V,mayor ,c, f ,mayor

fsi fsiffun

Page 72: Examenes resueltos

[ ]( )

[ ]

( )

fun comprobar V 1..n de elemento, x : elemento, c, f : nat dev valido : bool

veces := 0para i = c hasta f hacer

si V i = x entonces veces := veces +1 fsifparavalido := veces > f - c+1 div2

ffun

Para calcular el coste podemos utilizar la siguiente recurrencia:

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Tenemos a=2, b=2, k=1; ( ) ( )logT n n n∈Θ

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto).

Page 73: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2000 Reserva Cuestión 1. En el algoritmo quicksort, ¿qué implicaciones tiene para la eficiencia el escoger como pivote la mediana exacta del vector?. Cuestión 2. Los algoritmos de Prim y Kruskal calculan, de distintas formas, el árbol de expansión mínimo de un grafo. ¿Cuál de los dos es más eficiente para un grafo con alta densidad de aristas?. Razonar la repuesta. Cuestión 3. Explicar cómo funciona el algoritmo que dota a un vector de la propiedad de montículo en tiempo lineal (no es necesario demostrar que ese es el coste). La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 74: Examenes resueltos
Page 75: Examenes resueltos

Proc Hundir(V[1...n],i)k iRepetirj kSi 2j n y V[2j] > V[k] entonces k 2j fsiSi 2j < n y V[2j +1] > V[k] entonces k 2j + 1 fsiIntercambiar V[j] y V[k]ha

←≤ ←

sta j = kFin_proc

RESPUESTAS EXAMEN Programación III. Septiembre 2000 Reserva Cuestión 1. En el algoritmo quicksort, ¿qué implicaciones tiene para la eficiencia el escoger como pivote la mediana exacta del vector?.(Respuesta en: Fundamentos de Algoritmia, pag. 266). El algoritmo Quicksort tiene un tiempo promedio de ( )nlognΟ . En la práctica es más rápido que la ordenación por montículo (heapsort) y la ordenación por fusión (mergesort) en un tiempo constante. Al ser un algoritmo recursivo sería ideal poder dividir el caso en subcasos de tamaños similares de manera que cada elemento sea de profundidad logn , es decir, poder equilibrar los subcasos. Sin embargo, aunque seleccionemos la mediana del vector en el peor caso (todos los elementos a ordenar son iguales) el orden será cuadrático. Para obtener alguna ventaja utilizando como pivote la mediana tendremos que hacer algunas modificaciones al algoritmo original. Utilizaremos una nueva función pivote que divida en tres secciones el vector, de modo que dado un pivote p una parte conste de elementos menores que él, otra de elementos iguales y finalmente otra parte con los más grandes que p. Tras hacer esto se harían las llamadas recursivas correspondientes al algoritmo, una para con el sub-vector de elementos menores que p, y otra para el de los mayores que p. Esta modificación consigue que, utilizando la mediana como pivote el orden del algoritmo sea ( )nlognΟ incluso en el peor caso. Pero el coste que implica esta modificación hace que el tiempo constante crezca haciendo mejor el algoritmo de ordenación por montículo que el Quicksort en todos los casos, lo que hace que la modificación no sea factible. Cuestión 2. Los algoritmos de Prim y Kruskal calculan, de distintas formas, el árbol de expansión mínimo de un grafo. ¿Cuál de los dos es más eficiente para un grafo con alta densidad de aristas?. Razonar la repuesta. (Respuesta en: Fundamentos de Algoritmia, pag. 223). El algoritmo de Kruskal tiene un tiempo ( ) a log nΘ , siendo a el número de aristas. Si la densidad es

alta el número de aristas a tiende a ser n(n-1)/2, con lo que el tiempo pasaría a ( )2n lognΘ , y el algoritmo de Prim podría implementarse de forma que fuera mejor. En el caso de un grafo disperso (pocas aristas) el número de aristas tendería a n, siendo en este caso el tiempo ( )nlognΘ , siendo mejor que algunas implementaciones del algoritmo de Prim. Pero si implementamos el algoritmo de Prim utilizando montículos el tiempo requerido será de ( ) a log nΘ (al igual que el algoritmo de Kruskal). Cuestión 3. Explicar cómo funciona el algoritmo que dota a un vector de la propiedad de montículo en tiempo lineal (no es necesario demostrar que ese es el coste). (Respuesta en: Fundamentos de Algoritmia, pag. 190) El algoritmo que convierte un vector en un montículo en tiempo lineal es:

Proc CrearMontículo (V[1...N])Para i n/2 bajando hasta 1 hacerhundir(V,i)

Fin_proc

←⎢ ⎥⎣ ⎦

Page 76: Examenes resueltos

La idea es considerar el vector como un montículo, empezamos convirtiendo inicialmente en montículos los sub-árboles del nivel más bajo, para progresivamente seguir modificando en niveles superiores sucesivos. Veamos su funcionamiento con un ejemplo V=[4,3,7,7,10,1] con n=6 Si consideramos este vector cómo un montículo tendremos... Ejecutaríamos el algoritmo CrearMontículo

3 3

Para i 3 hasta 1 hundir(V,i)i = 3, hundir (V,3)k = , j =

no habría ningún cambio dado que V[6] < V[3] V=[4,3,7,7,10,1] k=j fin del bucle i=2 hundir (V,2) k=2, j=2 Como V[4]>V[2] k = 4 Pero V[5]>V[2], k=5 intercambia V[5],V[2] V=[4,10,7,7,3,1] k=5 y j=5, termina el bucle. i=1 hundir (V,1) k=1, j=1 Resulta que V[2]>V[1] k=2 Y NO (V[3] > V[2]) Intercambia V[2],V[1] V=[10,4,7,7,3,1] k=2, j=2 Como V[4]>V[2] k = 4 Pero NO(V[3]>V[4]) así que k=4 Intercambia V[4],V[2] V=[10,7,7,4,3,1] k=3, j=3 NO(V[6]>V[4]) con lo que no hay cambio y termina el bucle. Hemos obtenido finalmente el montículo. Si dibujamos los vectores como montículos, observamos que el proceso es el descrito anteriormente, vamos al nivel más bajo y obtenemos los montículos correspondientes. Y así sucesivamente hasta llegar a la raíz.

Page 77: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2001 – Primera semana Cuestión 1. (1 punto). Dado el siguiente montículo: [10,6,3,5,2,3,2] se pide insertar el valor 6 describiendo toda la secuencia de cambios en el mismo. Cuestión 2. (2 puntos). Suponemos que para el juego del ajedrez hemos programado una función estática perfecta de evaluación eval(u) para cada situación de juego u. Se supone conocida otra función, compleciones(u) que devuelve la lista de las jugadas legales a partir de la posición del tablero u. Explica, incluyendo pseudocódigo si es preciso, como programar un algoritmo que juegue al ajedrez. ¿Qué pasa si (como ocurre en la realidad) la función eval(u) no existe?¿Qué papel desempeña entonces la estrategia MINIMAX? Cuestión 3. (2 puntos). Un vector T contiene n elementos. Se quieren encontrar los m mayores elementos del vector y se supone que n >>m. Describe una forma eficiente de hacer esto sin ordenar el vector y calcula qué coste tiene. PROBLEMA (5 puntos). A orillas del río Guadalhorce, se encuentran 3 alumnos y 3 profesores del tribunal de la UNED que deben cruzar el río para ir juntos al Centro Asociado. Se dispone de una pequeña canoa de 2 plazas. Diseñar un algoritmo que encuentre una solución al problema de cruzar el río considerando las siguientes restricciones:

• La canoa no puede viajar sola. • En ningún momento puede haber grupos en las orillas donde el número de

alumnos supere al de los profesores. Diseñar ahora el algoritmo para que calcule la solución con menor número de movimientos. Explica los cambios que hay que hacer al anterior algoritmo. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 78: Examenes resueltos
Page 79: Examenes resueltos

Proc Flotar(T[1...n],i)k iRepetirj k

Si j > 1 y T[j/2] < T[k] entonces k j/2

Intercambiar T[j] y T[k]Hasta j = k

Fproc

RESPUESTAS EXAMEN Programación III. Febrero 2001 (Primera Semana) Cuestión 1.Dado el siguiente montículo [10,6,3,5,2,3,2] se pide insertar el valor 6 describiendo toda la secuencia de cambios en el mismo. El algoritmo de inserción es el siguiente:

Proc añadir - nodo (T[1...n],v)T[n+1] vFlotar(T[1...n+1],n+1)

Fproc

De este modo, dado el montículo [10,6,3,5,2,3,2], añadimos 6 al final [10,6,3,5,2,3,2,6] y procedemos a comparar y subir T[n+1] para cada sub-árbol hasta no tener que hacer ningún cambio. Veamos como iría cambiando: Se llamaría a flotar (T[1...8],8). Se compara T[8] con su padre, que viene dado por T[8/2]=4, como es mayor se intercambiaría resultando [10,6,3,6,2,3,2,5]. El valor de k queda actualizado a 4. Se vuelven a comparar T[4] y T[2], como son iguales no se hace nada y j queda igual que k, luego termina el bucle. Cuestión 2. Suponemos que para el juego del ajedrez hemos programado una función estática perfecta de evaluación eval(u) para cada situación de juego u. Se supone conocida otra función, compleciones (u) que devuelve la lista de las jugadas legales a partir de la posición del tablero u. Explica, incluyendo pseudocódigo si es preciso, como programar un algoritmo que juegue al ajedrez. ¿Qué pasa si (como ocurre en la realidad) la función eval(u) no existe?¿Qué papel desempeña entonces la estrategia MINIMAX? (Respuesta: Fundamentos de Algoritmia, pag.355) Gracias a la información perfecta suministrada por la función eval(u) podremos saber en cada momento cuál es la mejor jugada posible. De este modo si jugaran por ejemplo las blancas dado un estado u, tomaríamos como mejor movimiento el que maximice el valor de eval(u) (suponiendo que eval(u) nos devuelve el valor más grande cuanto mejor sea la jugada para las blancas), sin importarnos qué decisión puedan tomar las negras tras nuestro movimiento, ya que eval(u) nos asegura que nuestro movimiento es el más acertado. Sin embargo no existe una función eval(u) perfecta en el caso del ajedrez, deberemos entonces buscar una función eval aproximada con una relación coste/precisión lo mejor posible. En este caso, eval(u) no nos confirma que el mejor movimiento considerado por ella sea en realidad el más adecuado. Y es aquí donde entra la estrategia MINIMAX, considerando que si para las blancas será la mejor jugada la marcada como mayor valor de eval(u), las negras ejecutarán aquella que minimice dicho valor. De este modo si queremos anticipar un número determinado de jugadas, tomaremos al anterior criterio, minimizar el valor de eval(u) paras las negras y maximizarlo paras las blancas.

Page 80: Examenes resueltos

Cuestión 3. Un vector T contiene n elementos. Se quieren encontrar los m mayores elementos del vector y se supone que n >>m. Describe una forma eficiente de hacer esto sin ordenar el vector y calcula qué coste tiene. Podemos utilizar un enfoque similar a como hacemos en la ordenación por fusión, pero en este caso iremos generando un sub-vector con aquellos elementos mayores que m. Dividimos por tanto el vector original de forma equilibrada y progresivamente, hasta llegar a un tamaño base adecuado (lo suficientemente pequeño) para aplicar en el la búsqueda de todo elemento menor que m, cada vez que encontremos un elemento menor que m lo almacenaremos en un vector resultado, que posteriormente se fusionará con los encontrados en las distintas llamadas. Igualmente podemos utilizar otro algoritmo de Ordenación pero sin ordenar el vector, si no almacenar en otro vector los índices en el orden correspondiente, por ejemplo.

Page 81: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2001 – Segunda semana Cuestión 1. (1 punto). Mostrar mediante un ejemplo que el algoritmo de Dijkstra no siempre encuentra el camino mínimo si existe una distancia negativa. Cuestión 2. (2 puntos). Poner un ejemplo de un vector de 10 elementos que suponga un ejemplo de caso peor para el algoritmo de ordenación Quicksort. Ordenar el vector mediante este algoritmo detallando cada uno de los pasos. Cuestión 3. (2 puntos). Dado un montículo T[1...n] programar completamente en pseudocódigo una función recursiva flotar(T,i) para flotar el elemento de la posición i del vector T. Explica como usar esta función para insertar un elemento en el montículo. PROBLEMA (5 puntos). Se tiene que organizar un torneo con n participantes (con n potencia de 2). Cada participante tiene que competir exactamente una vez con todos los posibles oponentes. Además cada participante tiene que jugar exactamente 1 partido al día. Se pide construir un algoritmo que permita establecer al calendario del campeonato para que concluya en n-1 días. Sugerencia: dos grupos disjuntos de m jugadores pueden jugar entre ellos en m días mediante rotación. Ejemplo: a,b,c contra d,e,f juegan: Día 1: ad, be y cf. Día 2: ae, bf, y cd. Y finalmente Día 3: af, bd y ce. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 82: Examenes resueltos
Page 83: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2001 (Segunda Semana) Cuestión 1.Mostrar mediante un ejemplo que el algoritmo de Dijkstra no siempre encuentra el camino mínimo si existe una distancia negativa. (Respuesta: Fundamentos de Algoritmia pag. 224) El algoritmo de Dijkstra nos devuelve los caminos mínimos desde el origen, y su pseudo código es: Probaremos este algoritmo para el siguiente grafo:

F Dijkstra (L[1...n,1..n]) : matriz [2...n]Matriz D[2...n]InicializaciónC 2,3,....nPara i 2 hasta n hacer D[i] L[1,i] Finpara←

← ←

Bucle vorazRepetir n - 2 veces

v algún elemento de C que minimiza D[v]C C \ vPara cada w C h

←←

acerD[w] min (D[w], D[v] + L[v,w])

FinparaFinRepiteFinpara

FFunción

Observando el grafo apreciamos los caminos más cortos desde 1 a cualquier nodo son: 1-2 con coste 2, 1-3 con coste 4, 1-3-5 con coste 9, 1-3-5-6 con coste 0 y 1-3-5-6-4 con coste 1, veremos si el algoritmo de Dijkstra nos devuelve esta solución. Tenemos para cada paso y tras la inicialización...

Distancias desde 1 Nodo Precedente

Paso Nodo Seleccionado

Nodo No Seleccionado 2 3 4 5 6 2 3 4 5 6

Inicializa 1 2,3,4,5,6 2 4 ∞ ∞ ∞ 1 1 1 1 1 1 1,2 3,4,5,6 2 4 3 ∞ ∞ 1 1 2 1 1 2 1,2,4 3,5,6 2 4 3 ∞ ∞ 1 1 2 1 1 3 1,2,4,3 5,6 2 4 3 9 ∞ 1 1 2 3 1 4 1,2,4,3,5 6 2 4 3 9 0 1 1 6 3 5

Observamos como la solución devuelta no es la correcta ya que los costes no son los mínimos, con lo que los caminos serían 1-2 (coste 2), 1-2-4 (coste 3) aquí está el fallo, porque una vez que se añade el nodo al conjunto S establece el camino mínimo y ya no puede modificarse como ocurre aquí, 1-3 (coste 4), 1-3-5(coste 9) y 1-3-5-6 (coste 0).

Page 84: Examenes resueltos

.. ..

Proc quicksort(T[i...j])Si j - i es suficientemente pequeño entonces insertar (T[i...j] ) Sino Pivote (T[i...j],L) Quicksort (T[i L -1]) Quicksort(T[L+1 j]) FsiFin_proc

Cuestión 2. Poner un ejemplo de un vector de 10 elementos que suponga un ejemplo de caso peor para el algoritmo de ordenación Quicksort. Ordenar el vector mediante este algoritmo detallando cada uno de los pasos. (Respuesta Fundamentos de Algoritmia, pag 261) Tomaremos un vector con 10 elementos ya ordenados como peor caso. 1,2,3,4,5,6,7,8,9,10 El algoritmo Quicksort es...

Proc pivote(T[i...j],var L )p T[i]k i ; L j +1repetir k k +1 hasta que T[k] > p o k >= j fin_repiterepetir L L 1 hasta que T[L] <= p fin_repite

←← ←

← −

mientras k < L hacerIntercambiar T[k] y T[L]repetir k k +1 hasta que T[k] > p fin_repite

repetir L L+1 hasta que T[L] <= p fin_repite

fmientrasintercambiar T[i] y T[L]

Fin_proc

T[1..10]=1,2,3,4,5,6,7,8,9,10 Pivote(T[1..10], L) Luego i=1 y j=10 p=1, k=1, L=11 1. primer bucle, se mueve k hasta 2, ya que T[2]>p 2. segundo bucle, L llega hasta 1, ya que es el único elemento tq T[L]<=p Llegamos al 3er bucle k=2 y L=1 (k>L), no existe por tanto intercambio alguno, excepto la última instrucción Intercambiar T[i] por T[L], como L apunta a 1, e i es uno T[L] queda igual. A continuación se llamaría a: Quicksort(T[1...0]), Llamada a un caso de tamaño cero. Quicksort (T[2....10]). Llamamos al resto del vector. Ignoramos la primera llamada al ser de un tamaño 0, la segunda llamada tendría el mismo efecto que la primera vez, en este caso en el procedimiento pivote L descendería hasta llegar al T[2], y k quedaría en el tercer elemento; no se provoca cambio alguno, y vuelve a hacerse una tercera llamada a Quicksort, una de ellas para un caso de tamaño 0: Quicksort(T[2..1]), y otra para el resto del vector, Quicksort(T[3...10]). Como vemos el proceso se repite hasta llegar al último elemento, produciéndose tantas llamadas como elementos posee el vector.

Page 85: Examenes resueltos

[ ]( )

( )

( )( )

,

Proc crear_monticulo T 1..n ,i

si i > ndevuelve T

sinoflotar T i

crear_monticulo T,i+1fsi

fproc

[ ]( )

( ) [ ] [ ][ ] [ ]( )

( )

,

,

Proc Flotar i T 1...n ;

i_padre := i div 2;Si i > 1 y T i T i_padre entonces

Intercambiar T i T i_padre ;

Flotar i_padre,T ;fFlotar;

>

Cuestión 3. Dado un montículo T[1...n] programar completamente en pseudocódigo una función recursiva flotar(T,i) para flotar el elemento de la posición i del vector T. Explica como usar esta función para insertar un elemento en el montículo. (Respuesta. Fundamentos de Algoritmia, pag. 188) Tomar el algoritmo iterativo de la pag 188 y transformar en recursivo. La llamada inicial será ( )_ , 2crear monticulo T . Otra versión pero en este caso sin usar funciones auxiliares es sustituir el código de flotar por su versión iterativa e insertarlo en la función anterior. Para insertar un elemento en el montículo utilizo:

[ ]( )[ ]

[ ]( )

;

Proc añadir_nodo T 1..n ,v

T n+1 v;

Flotar T 1..n+1 ,n+1

FProc;

PROBLEMA (5 puntos). Se tiene que organizar un torneo con n participantes (con n potencia de 2). Cada participante tiene que competir exactamente una vez con todos los posibles oponentes. Además cada participante tiene que jugar exactamente 1 partido al día. Se pide construir un algoritmo que permita establecer al calendario del campeonato para que concluya en n-1 días. Sugerencia: dos grupos disjuntos de m jugadores pueden jugar entre ellos en m días mediante rotación. Ejemplo: a,b,c contra d,e,f juegan: Día 1: ad, be y cf. Día 2: ae, bf, y cd. Y finalmente Día 3: af, bd y ce. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 86: Examenes resueltos
Page 87: Examenes resueltos

Escuela Tecnica Superior de Ingenieros Informaticos de la UNED

Ingeniera Tecnica de Sistemas e Ingeniera Tecnica de Gestion

Programacion III - Convocatoria de Septiembre de 2001

Original

Cuestion 1 (2 punto). Halla el grafo de expansion mnimo del grafo de la gura medianteel algoritmo de Kruskal. Detalla cada paso.Cuestion 2 (1 punto). Explica porque una estructura de montculo suele ser adecuadapara representar el conjunto de candidatos en un algoritmo voraz.Cuestion 3 (1 punto). Explica en que consiste un problema de planicacion con plazojo. Pon un ejemplo con n = 4 y resuelvelo aplicando el algoritmo voraz correspondiente.

Problema 2 (5 puntos). Se plantea el siguiente juego: Tenemos un rectangulo (tablero)de n las y m columnas con nm casillas y suponemos que el tablero descansa sobre unode sus lados de tama~nom al que denominaremos base, y donde cada casilla puede contenersmbolos de k tipos diferentes. Al comienzo del juego el usuario comienza con un tablerolleno de smbolos. En cada movimiento el jugador elige un smbolo del tablero y este eseliminado del mismo junto con (si las hay) las agrupaciones adyacentes (en horizontal overtical) de su mismo smbolo siempre que mantengan la continuidad. Una vez eliminadala agrupacion, los huecos dejados por esta se rellenan deslizando hacia la base los smbolosde su columna que queden por encima del hueco dejado por los smbolos eliminados. Elobjetivo del juego es el de dejar el tablero vaco.

Para ilustrar el enunciado supongamos un tablero de 4 las y 5 columnas con 4 smboloso,+,*,x y donde - representa una casilla vaca. Una secuencia de juego sera la siguiente:

oox+x --x+x ---+x ----- ----- ----- ----- -----

o++x+ --+x+ ---x+ ---+- ----- ----- ----- -----

o**ox -+*ox --xox --xxx ---+- ---+- ----- -----

oo*xx -**xx -++xx -++o+ -++o+ ---o+ --++- -----

Se pide programar un algoritmo que resuelva el juego. Explicar ademas (si las hay) lasdiferencias que habra que introducir a este algoritmo si se exigiera resolver el juego en elmenor numero de movimientos.

La resolucion de cada problema debe incluir, por este orden: Eleccion razonada del esquema

algortmico. Breve descripcion del esquema usado e identicacion con el problema. Estructuras

de datos requeridas. Algoritmo completo a partir del renamiento del esquema general. Estudio

del coste.

Segun el esquema elegido hay que especicar, ademas: Voraz: demostracion de optimalidad.

Divide y venceras: preorden bien fundado entre los ejemplares del problema. Exploracion en

grafos: descripcion del grafo de busqueda asociado.

Page 88: Examenes resueltos
Page 89: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2001 (Original) Cuestión 1.Comenta de qué formas se puede mejorar la eficiencia del algoritmo de Dijkstra mediante el uso de estructuras de datos apropiadas. (Respuesta. Fundamentos de Algoritmia. Pag 227) Utilizando una matriz de adyacencia y matrices para representar los datos el algoritmo se sitúan en ( )2nΟ (con un tiempo ( )nΟ para inicializar la matriz de adyacencia y un tiempo ( )2nΘ en los bucles

que conforman el algoritmo voraz). Si resulta que el número de aristas a es mayor que el número de nodos al cuadrado, 2n , resulta apropiado utilizar en vez de una matriz de adyacencia, una lista de adyacencia, evitando examinar entradas innecesarias -dónde no existe arista- , ahorrando así tiempo en el bucle más interno del algoritmo. Por otro lado podemos utilizar un montículo invertido para representar el camino mínimo que se irá generando (que llamaremos D), esto hace que buscar un nodo que minimice el costo requiera sólo eliminar la raíz del montículo lo que conlleva un gasto de O(log n) , siendo la inicialización del montículo ( )nΘ . Igualmente las operaciones empleadas en el bucle más interno del algoritmo reducirán su coste (al ser D un montículo), situándose en O(log n) . Si se produce la eliminación de la raíz del montículo n-2 veces (el bucle se ejecuta n-2 veces) y hay que flotar un máximo de a nodos (siendo a el número de aristas) obtenemos un tiempo total de

((a+n) log n)Θ . Si el grafo es conexo, es decir, a >= n -1 el tiempo corresponde a (a log n)Θ . Si el grafo es denso será preferible la implementación con matrices, si el grafo es disperso es mejor la implementación con montículos. Cuestión 2. Explica porqué una estructura de montículo suele ser adecuada para representar el conjunto de candidatos de un algoritmo voraz. En un algoritmo voraz iremos eligiendo el candidato más apropiado a cada paso para la hallar la solución según el valor de una función de selección. Para agilizar esa elección podemos tener dichos candidatos almacenados en un montículo, de forma que el valor considerado para su mantenimiento sea el valor de dicha función de selección. De este modo la elección de candidato consistirá en ir escogiendo la cima de dicho montículo y actualizar este cuando así proceda, operaciones estas que resultan más eficientes en los montículos que en otros tipos de estructura de datos. Cuestión 3. Explica en que consiste un problema de planificación con plazo fijo. Pon un ejemplo con n=4 y resuélvelo aplicando el algoritmo correspondiente. (Respuesta: Fundamentos de Algoritmia pag.233) Un problema de planificación con plazo fijo consiste en: Dado un conjunto de n tareas, cada una de las cuales requiere un tiempo unitario, en cualquier instante T=1,2,... podemos ejecutar únicamente una tarea. Cada tarea nos producirá un beneficio mayor que cero, sólo en el caso en el que su ejecución sea en un instante anterior a di. Habrá que buscar la secuencia de tareas más apropiada de manera que el beneficio obtenido sea mayor. (Bastaría con aplicar el algoritmo que aparece en la pag. 240, ilustrado con un ejemplo para seis tareas, como se ve la solución bastaría con eliminar las tareas 5 y 6 y el resultado sería igual con lo que ya tenemos un ejemplo con n=4

i 1 2 3 4 beneficio 20 15 10 7 tiempo 3 1 1 3 Observar que tenemos las tareas ya ordenadas según su beneficio de mayor a menor, si no fuera así para utilizar el algoritmo convendría proceder a esta ordenación)

Page 90: Examenes resueltos
Page 91: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2001 Reserva Cuestión 1.Compara la eficiencia de los algoritmos de ordenación Quicksort y Mergesort. Cuestión 2. Programa un algoritmo recursivo para implementar la operación de hundir un elemento i en un montículo representado por el vector T[1...n] (Se supone que salvo por T[i], el vector T posee la propiedad del montículo). (Respuesta Fundamentos de Algoritmia, pag 188) Cuestión 3. En los algoritmos de vuelta atrás explica la diferencia entre una condición de poda y una condición de retroceso. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 92: Examenes resueltos
Page 93: Examenes resueltos

( )

,

Proc Hundir(i V[1...n])k iSi 2i n y V[2i] > V[k] entonces k 2i fsiSi 2i n y V[2i+1] > V[k] entonces k 2i + 1 fsiSi k > i entoncesIntercambiar V[i] y V[k]

hund

←≤ ←≤ ←

( ),ir k VFin_proc

[ ]( )

( )

( )( )

Proc crear_monticulo V 1..n ,i

si i 1devuelve V

sinohundir i,V

crear_monticulo V,i 1fsi

fproc

<

Proc Intercambiar(int j,k); var aux; aux :=V[j]; V[j] :=V[k]; V[k] := aux;Fproc Intercambiar;

RESPUESTAS EXAMEN Programación III. Septiembre 2001 (Reserva) Cuestión 1.Compara la eficiencia de los algoritmos de ordenación Quicksort y Mergesort. El algoritmo Quicksort emplea un tiempo promedio de nlogn, en el peor caso de n2. El algoritmo por fusión Mergesort utiliza un tiempo de nlogn (siempre observando la precaución de equilibrar los subcasos a tratar). Pese a esto, en la práctica Quicksort es más rápido en un tiempo c constante. Además el algoritmo Mergesort requiere de un espacio extra para tratar los distintos casos sin perder eficiencia (hacer la ordenación in situ lleva asociado un incremento de la constante oculta bastante alto). Cuestión 2. Programa un algoritmo recursivo para implementar la operación de hundir un elemento i en un montículo representado por el vector T[1...n] (Se supone que salvo por T[i], el vector T posee la propiedad del montículo). (Respuesta Fundamentos de Algoritmia, pag 188)

Proc añadir - nodo (T[1...n],v)T[n+1] vFlotar(T[1...n+1],n+1)

Fproc

Cuestión 3. En los algoritmos de vuelta atrás explica la diferencia entre una condición de poda y una condición de retroceso. El algoritmo de vuelta atrás básico consiste en una búsqueda exhaustiva en el árbol, si el recorrido del árbol no tiene éxito porque la solución parcial hasta ese momento no puede ser completada se produce un retroceso, igualmente si ya existiera una solución mejor a la que está siendo actualmente calculado volveríamos atrás. Si queremos limitar más aún nuestro espacio de búsqueda podemos utilizar condiciones de poda, dado un determinado problema intentamos encontrar información que nos permita decidir detener la búsqueda (volviendo consecuentemente atrás) si hay claros indicios de que el estado actual no nos conducirá a una solución. En vuelta atrás no hay condición de poda, sólo comprobación de que las soluciones parciales son k-prometedoras antes de continuar la exploración del grafo. Lourdes Araujo.

Page 94: Examenes resueltos
Page 95: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2002 – Primera semana Cuestión 1 (2 puntos). Describir la estrategia de selección voraz para el problema de la planificación con un plazo fijo. Aplicarla a la resolución del siguiente ejemplo detallado cada paso: Tarea i 1 2 3 4 5 6 Instante di 4 3 1 1 2 2 Beneficios gi 10 30 20 30 50 20 Cuestión 2 (1 puntos). Explica la diferencia entre una condición de poda y una condición de retroceso en el esquema de búsqueda vuelta atrás. Cuestión 3 (2 puntos). Programar en pseudocódigo un algoritmo recursivo para la operación de hundir un elemento en un montículo. Problema (5 puntos). Una caja con n bombones se considera “aburrida” si se repite un mismo tipo de bombón (denominado bombón pesado) más de n/2 veces. Programar en pseudocódigo un algoritmo que decida si una caja es “aburrida” y devuelva (en su caso) el tipo de bombón que le confirme dicha propiedad. El coste debe ser a lo sumo O(n log n). NOTA: Si una caja tiene un bombón pesado, entonces necesariamente también lo es al menos una de sus mitades. (Resuelto Universidad de Málaga pag 121, y EDMA 331). La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 96: Examenes resueltos
Page 97: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2002 (Primera Semana) Cuestión 1 (2 puntos). Describir la estrategia de selección voraz para el problema de la planificación con un plazo fijo. Aplicarla a la resolución del siguiente ejemplo detallado cada paso: Tarea i 1 2 3 4 5 6 Instante di 4 3 1 1 2 2 Beneficios gi 10 30 20 30 50 20 Lo primero lo ordeno en función de los costes de forma decreciente. Tarea i 5 2 4 3 6 1 Instante di 2 3 1 1 2 4 Beneficios gi 50 30 30 20 20 10 Aplico el algoritmo y calculo ( )( )min 6, max ip d= → ( )min 6, 4 4p = = Para d1 = 2 Se asigna la Tarea 5 en la posición 2 5 Para d2 = 3 Se asigna la Tarea 2 en la posición 3 5 2 Para d3 = 1 Se asigna la Tarea 4 en la posición 1 4 5 2 Para d4 =1 No hay posiciones Libres Para d5 = 2 No hay posiciones Libres Para d6 = 4 Se asigna la Tarea 1 en la posición 4 4 5 2 1 La secuencia óptima es 4,5,2,1. Con un valor de 120. Cuestión 2 (1 puntos). Explica la diferencia entre una condición de poda y una condición de retroceso en el esquema de búsqueda vuelta atrás. El algoritmo de vuelta atrás básico consiste en una búsqueda exhaustiva en el árbol, si el recorrido del árbol no tiene éxito porque la solución parcial hasta ese momento no puede ser completada se produce un retroceso, igualmente si ya existiera una solución mejor a la que está siendo actualmente calculado volveríamos atrás. Si queremos limitar más aún nuestro espacio de búsqueda podemos utilizar condiciones de poda, dado un determinado problema intentamos encontrar información que nos permita decidir deterger la búsqueda (volviendo consecuentemente atrás) si hay claros indicios de que el estado actual no nos conducirá a una solución.

Page 98: Examenes resueltos

( )

,

Proc Hundir(i V[1...n])k iSi 2i n y V[2i] > V[k] entonces k 2i fsiSi 2i n y V[2i+1] > V[k] entonces k 2i + 1 fsiSi k > i entoncesIntercambiar V[i] y V[k]

hund

←≤ ←≤ ←

( ),ir k VFin_proc

Proc Intercambiar(int j,k); var aux; aux :=V[j]; V[j] :=V[k]; V[k] := aux;Fproc Intercambiar;

Cuestión 3 (2 puntos). Programar en pseudocódigo un algoritmo recursivo para la operación de hundir un elemento en un montículo. Problema (5 puntos). Una caja con n bombones se considera “aburrida” si se repite un mismo tipo de bombón (denominado bombón pesado) más de n/2 veces. Programar en pseudocódigo un algoritmo que decida si una caja es “aburrida” y devuelva (en su caso) el tipo de bombón que le confirme dicha propiedad. El coste debe ser a lo sumo O(n log n). NOTA: Si una caja tiene un bombón pesado, entonces necesariamente también lo es al menos una de sus mitades. (Resuelto Universidad de Málaga pag 121, y EDMA 331). 1. Elección razonada del esquema algorítmico No es un problema de optimización, por lo tanto descarto el esquema voraz y ramificación y poda, como nos piden que el coste sea logarítmico y el problema se puede dividir en subproblemas más pequeños utilizaré el esquema de divide y vencerás. ESQUEMA GENÉRICO. función divide y vencerás (problema) si suficientemente simple (problema) entonces devolver solución simple (problema) sino hacer p1 … pk ← descomponer (problema)

para cada pi hacer si ← divide_y_vencerás (pi) fpara

devolver combinación (s1, ..., sk) fsi ffunción

Si el vector tiene un elemento mayoritario, este tiene que ser mayoritario en al menos una de las mitades del vector. Utilizando esta idea, podemos mirar de forma recursiva si existe un elemento mayoritario en cada una de las dos mitades del vector y si aparece en más de la mitad de las posiciones, será el elemento mayoritario buscado. El algoritmo que busca el mayoritario de [ ]..V c f es el siguiente:

Page 99: Examenes resueltos

[ ]( )[ ]

( )( )1 1

fun mayoritario V 1..n de elemento, c, f : nat dev existe : bool, mayor : elemento

si c = f entonces existe, mayor := cierto, V c

sino m := c+ f div2

existe , mayor := mayoritario V,c,m

( )

( )

2 2

1

1 1

existe , mayor := mayoritario V,m+1, f existe := falso si existe entonces comprobamos el primer candidato

existe, mayor := comprobar V,mayor ,c, f ,mayor

fsi

( )2

2 2

si ¬existe existe entonces comprobamos el segundo candidato

existe, mayor := comprobar V,mayor ,c, f ,mayor

fsi fsiffun

[ ]( )

[ ]

( )

fun comprobar V 1..n de elemento, x : elemento, c, f : nat dev valido : bool

veces := 0para i = c hasta f hacer

si V i = x entonces veces := veces +1 fsifparavalido := veces > f - c+1 div2

ffun

Para calcular el coste podemos utilizar la siguiente recurrencia:

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Tenemos a=2, b=2, k=1; ( ) ( )logT n n n∈Θ

Page 100: Examenes resueltos
Page 101: Examenes resueltos

Escuela Universitaria de Informatica de la UNED

Ingenierıa Tecnica de Sistemas e Ingenierıa Tecnica de Gestion

Programacion III - Febrero 2.002 - Segunda Semana

Cuestion 1 (1 puntos). Escribe la secuencia completa de pasos para or-denar por fusion el vector [3,2,7,5,9,3,4,8].

Cuestion 2 (1 punto). Un algoritmo de coste O(n2) tarda 15 segundosen realizar un determinado procesamiento sobre un ordenador a 450 MHz.¿Cuanto tiempo se tarda en realizar el mismo procesamiento con el mismoalgoritmo sobre una maquina 3 veces mas lenta?

Cuestion 3 (3 puntos). Programar en pseudocodigo todos los proce-dimientos necesarios para fusionar dos conjuntos implementados con montıculos.Suponer que los conjuntos no pueden tener elementos repetidos.

Problema (5 puntos). Se dispone de un tablero de 8 casillas similar alque muestra la figura. En la situacion inicial, las casillas estan ocupadas porcuatro O y cuatro X distribuidas de forma aleatoria. En cada paso la unicaoperacion posible es intercambiar dos fichas adyacentes. Programar de laforma mas eficiente posible el algoritmo que devuelva la secuencia de pasosmas corta para ordenar el tablero de forma que todas las fichas tengan almenos otra igual adyacente.

X O X X O O O X

La resolucion del problema debe incluir, por este orden:

1. Eleccion razonada del esquema algorıtmico.

2. Descripcion del esquema usado e identificacion con el problema.

3. Estructuras de datos.

4. Algoritmo completo a partir del refinamiento del esquema general.

5. Estudio del coste.

Segun el esquema elegido hay que especificar, ademas:

• Voraz: demostracion de optimalidad.

• Divide y venceras: preorden bien fundado.

• Exploracion en grafos: descripcion del arbol de busqueda asociado.

Page 102: Examenes resueltos
Page 103: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2002 – Original Cuestión 1 (2 puntos). En el algoritmo de ordenación por montículo (heapsort). ¿Cuáles son las mejores y peores disposiciones iniciales de los ejemplos que hay que ordenar en cuanto al tiempo de ejecución? Razonar la respuesta y poner ejemplos. Cuestión 2 (2 puntos). Aplicar el algoritmo de Dijkstra al grafo dirigido representado por la siguiente matriz adyacencia. 1 2 3 4 5

1 - 50 30 100 10 2 - - - - - 3 - 5 - -30 - 4 - 20 - - - 5 - - - 10 - Tomando el nodo 1 como nodo origen. ¿Encuentra los caminos mínimos? Si la respuesta es negativa ¿Cuáles serian los caminos mínimos y porque no los encuentra el algoritmo de Dijkstra? ¿Qué pasaría si se invierte el sentido de la arista que une el nodo 3 con el 2?. Cuestión 3 (1 punto). De los algoritmos de ordenación que has estudiado. ¿Cuál es el más eficiente en términos de coste asintótico temporal en el caso peor?. Razonar la respuesta. PROBLEMA (5 puntos). Escribir un algoritmo que descubra cómo encontrar el camino más corto desde la entrada hasta la salida de un laberinto (suponer que hay sólo una entrada y sólo una salida) La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 104: Examenes resueltos
Page 105: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2002(Original) Cuestión 1 (2 puntos). En el algoritmo de ordenación por montículo (heapsort). ¿Cuáles son las mejores y peores disposiciones iniciales de los ejemplos que hay que ordenar en cuanto al tiempo de ejecución? Razonar la respuesta y poner ejemplos. En el peor caso, la profundidad a la que hay que empujar las raíces respectivas es la máxima, y por tanto la complejidad de esta segunda parte del algoritmo es O(nlogn). ¿Cuándo ocurre esto? Cuando el elemento es menor que todos los demás. Pero esto sucede siempre que los elementos a ordenar sean distintos, por la forma en la que se van escogiendo las nuevas raíces. En el caso mejor, aunque el bucle se sigue repitiendo n–1 veces, las raíces no descienden, por ser mayores o iguales que el resto de los elementos del montículo. Así, la complejidad de esta parte del algoritmo es de orden O(n). Pero este caso sólo se dará si los elementos del vector son iguales, por la forma en la que originariamente se construyó el montículo y por cómo se escoge la nueva raíz en cada iteración (el último de los elementos, que en un montículo ha de ser de los menores). Cuestión 2 (2 puntos). Aplicar el algoritmo de Dijkstra al grafo dirigido representado por la siguiente matriz adyacencia. 1 2 3 4 5 1 50 30 100 10 2 3 5 -30 4 20 5 10 Tomando el nodo 1 como nodo origen. ¿Encuentra los caminos mínimos? Si la respuesta es negativa ¿Cuáles serian los caminos mínimos y porque no los encuentra el algoritmo de Dijkstra? ¿Qué pasaría si se invierte el sentido de la arista que une el nodo 3 con el 2?.

Distancias desde 1 Nodo Precedente PASO Nodo Seleccionado

Conjunto S Nodo No Seleccionado

Conjunto C 2 3 4 5 2 3 4 5 50 30 100 10 1 1 1 1 50 30 20 10 1 1 5 1 40 30 20 10 4 1 5 1

INICIO 1 2 3

1 1,5 1,5,4 1,5,4,3

2,3,4,5 2,3,4 2,3 2 20 30 0 10 4 1 3 1

El fallo está en el camino 1-5-4 que tiene como resultado 20, pero resulta no ser un camino mínimo al haber el camino 1-3-4 de valor 0. Se supone que una vez que se añade un nodo al conjunto S no se puede modificar la distancia.

3 4

2 5

1

5 10 20

50

-30

100

10

30

Page 106: Examenes resueltos

Cuestión 3 (1 punto). De los algoritmos de ordenación que has estudiado. ¿Cuál es el más eficiente en términos de coste asintótico temporal en el caso peor?. Razonar la respuesta. Quicksort: Mergesort: Montículo: PROBLEMA (5 puntos). Escribir un algoritmo que descubra cómo encontrar el camino más corto desde la entrada hasta la salida de un laberinto (suponer que hay sólo una entrada y sólo una salida)

( )( )

fun vuelta - atras(ensayo) si valido (ensayo) es una solucion entonces dev (ensayo) si no lista - ensayos compleciones ensayo

mientras ¬ vacia lista - ensayos ¬ resultado hacer

( )( )

hijo primero lista - ensayos

lista - ensayos resto lista - ensayos si condiciones de poda (hijo) hacer resultado vuelta - atras(hijo) fsi fmientras dev

resultado fsiffun

• El ensayo es un nodo del árbol. • La función válido determina si un nodo es solución al problema o no. • La función compleciones genera los hijos de un nodo dado. • La función condiciones de poda verifica si puede descartarse de antemano una rama del árbol,

aplicando los criterios de poda sobre el nodo origen. PROCEDURE Laberinto2(k:CARDINAL;VAR fil,col:INTEGER); VAR orden:CARDINAL; (*indica hacia donde debe moverse *) BEGIN orden:=0; REPEAT INC(orden); fil:=fil + mov_fil[orden]; col:=col + mov_col[orden]; IF (1<=fil) AND (fil<=n) AND (1<=col) AND (col<=n) AND (lab[fil,col]=0) THEN lab[fil,col]:=k; IF (fil=n) AND (col=n) THEN (* almacenamos el mejor recorrido hasta el momento *) recorridominimo:=k; solucion:=lab; ELSIF k<=recorridominimo THEN (* poda! *) Laberinto2(k+1,fil,col); END; lab[fil,col]:=0; END; fil:=fil - mov_fil[orden]; col:=col - mov_col[orden] UNTIL (orden=4) END Laberinto2;

Las variables mov_fil y mov_col contienen los posibles movimientos, y son inicializadas por el procedimiento MovimientosPosibles que mostramos a continuación:

Page 107: Examenes resueltos

VAR mov_fil,mov_col:ARRAY [1..4] OF INTEGER; PROCEDURE MovimientosPosibles; BEGIN mov_fil[1]:=1; mov_col[1]:=0; (* sur *) mov_fil[2]:=0; mov_col[2]:=1; (* este *) mov_fil[3]:=0; mov_col[3]:=-1; (* oeste *) mov_fil[4]:=-1; mov_col[4]:=0; (* norte *) END MovimientosPosibles;

En este caso hemos introducido una variante muy importante: el uso de una cota para podar ramas del árbol de expansión. Si bien ésta es una técnica que se utiliza sobre todo en los algoritmos de Ramificación y Poda (y de ahí su nombre), el uso de cotas para podar puede ser aplicado a cualquier tipo de árboles de expansión. En el problema que nos ocupa calculamos la primera solución y para ella se obtiene un valor. En este caso es el número de movimientos que ha realizado el algoritmo hasta encontrar la salida, que es el valor que queremos minimizar. Pues bien, disponiendo ya de un valor alcanzable podemos “rechazar” todos aquellos nodos cuyos recorridos superen este valor, sean soluciones parciales o totales, pues no nos van a llevar hacia la solución óptima. Estas podas ahorran mucho trabajo al algoritmo, pues evitan que éste realice trabajo innecesario. La variable recorridominimo, que es la que hace las funciones de cota, se inicializa a MAX(CARDINAL) al principio del programa principal que invoca al procedimiento Laberinto2(1,1,1). Como norma general para los algoritmos de Vuelta Atrás, y puesto que su complejidad es normalmente exponencial, debemos de saber aprovechar toda la información disponible sobre el problema o sus soluciones en forma de restricciones, pues son éstas la clave de su eficiencia. En la mayoría de los casos la diferencia entre un algoritmo Vuelta Atrás útil y otro que, por su tardanza, no pueda utilizarse se encuentra en las restricciones impuestas a los nodos, único parámetro disponible al programador de estos métodos para mejorar la eficiencia de los algoritmos resultantes.

Page 108: Examenes resueltos
Page 109: Examenes resueltos
Page 110: Examenes resueltos
Page 111: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Diciembre 2002 – Original Cuestión 1 (2 puntos). Dado un vector [ ]1..T n que alberga un montículo en [ ]1..T i , programar una función recursiva que flote el elemento 1i + . Cuestión 2 (2 puntos). Calcular la ecuación de recurrencia y hallar el coste del siguiente algoritmo:

( )

;

3

Procedimiento P(n)var i, j : enteros;

j 1; si n 1 entonces terminar; sino

para i 1 hasta 7 hacer P n div 2

para i 1 hasta 4n hacer j j 1

←≤

← ← +

Cuestión 3 (2 puntos). Ordenar ascendentemente mediante el algoritmo de Quicksort el vector V = [2,3,8,1,9,4,2,2,6,5,4,3,7,4] detallando todos los pasos. PROBLEMA (5 puntos). Se tienen dos polinomios de grado n representados por dos vectores [ ]0..n de enteros, siendo la posición i de ambos vectores la correspondiente al termino x del polinomio. Se pide diseñar un algoritmo que multiplique ambos polinomios, valorándose especialmente que sea con un coste más eficiente que ( )2nΟ ,

en concreto hay una solución fácil de hallar con coste ( )2log 3nΟ . La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 112: Examenes resueltos
Page 113: Examenes resueltos

[ ]( )

( ) [ ] [ ][ ] [ ]( )

( )

,

,

Proc Flotar i T 1...n ;

i_padre := i div 2;Si i > 1 y T i T i_padre entonces

Intercambiar T i T i_padre ;

Flotar i_padre,T ;fFlotar;

>

RESPUESTAS EXAMEN Programación III. Diciembre 2002 Cuestión 1 (2 puntos). Dado un vector [ ]1..T n que alberga un montículo en [ ]1..T i , programar una función recursiva que flote el elemento 1i + .

Llamada inicial (T,i+1) Cuestión 2 (2 puntos). Calcular la ecuación de recurrencia y hallar el coste del siguiente algoritmo:

( )

;

3

Procedimiento P(n)var i, j : enteros;

j 1; si n 1 entonces terminar; sino

para i 1 hasta 7 hacer P n div 2

para i 1 hasta 4n hacer j j 1

←≤

← ← +

El primer para es: Una asignación y 7 llamadas recursivas a = 7. El problema se llama recursivamente con ejemplares de tamaño n/2, ( b = 2). El segundo para será: desde 1 hasta 4n3. Por lo que el grado k del polinomio será 3 ( k = 3 ). La ecuación de recurrencia quedaría: a = 7, b = 2, k = 3. ( )3nΘ

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )b

k

k

log a

n

T n n logn

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Autor: MIGUEL RODRIGUEZ ARTACHO 7 veces p(n/2) y luego un proceso de coste 4n^3 a=7, b=2 y k=3 OK

Page 114: Examenes resueltos

Cuestión 3 (2 puntos). Ordenar ascendentemente mediante el algoritmo de Quicksort el vector V=[2,3,8,1,9,4,2,2,6,5,4,3,7,4] detallando todos los pasos. Pivote 2 3 8 1 9 4 2 2 6 5 4 3 7 4 2 3 4 1 9 4 2 2 6 5 4 3 7 8 2 3 4 1 3 4 2 2 6 5 4 9 7 8 2 3 4 1 3 4 2 2 4 5 6 9 7 8 2 1 4 3 3 4 2 2 4 5 6 9 7 8 1 2 4 3 3 4 2 2 4 5 6 9 7 8 1 2 2 3 3 4 2 4 4 5 6 9 7 8 1 2 2 2 3 4 3 4 4 5 6 9 7 8 1 2 2 2 3 3 4 4 4 5 6 9 7 8 1 2 2 2 3 3 4 4 4 5 6 7 9 8 1 2 2 2 3 3 4 4 4 5 6 7 8 9 PROBLEMA (5 puntos). Se tienen dos polinomios de grado n representados por dos vectores [ ]0..n de enteros, siendo la posición i de ambos vectores la correspondiente al termino x del polinomio. Se pide diseñar un algoritmo que multiplique ambos polinomios, valorándose especialmente que sea con un coste más eficiente que ( )2nΟ , en concreto hay una solución fácil de hallar con coste ( )2log 3nΟ . Solución: No es un problema de optimización así que descarto el esquema voraz y el de ramificación y poda, tampoco es una búsqueda por lo tanto no es posible utilizar un esquema de vuelta atrás. El problema se puede dividir en subproblemas así que utilizaré un esquema de divide y vencerás. La solución de orden cuadrático. En este caso, se descompone en mitades P(x) = Axn/2+B y Q(x) = Cxn/2 +D con A,B,C,D polinomios de grado n/2 sacando factor común xn/2 como se detalla en las expresiones. De esta forma se ve claramente que P·Q es (Axn/2 +B)·( Cxn/2+D) = AC xn + (AD+BC)xn/2 + BD lo que la solución conlleva 4 multiplicaciones de grado n/2. El coste sería en este caso cuadrático. Sin embargo hay una manera de organizar las operaciones mediante la cual, no es necesario calcular AD+BC mediante 2 productos, sino sólo con uno, aprovechando que ya tenemos realizados los productos BD y AC. En este último caso basta con observar que (A+B)·( C+D) = AC+BC+AD+BD y que BC+AD = (A+B)·( C+D) – AC – BD con lo que es posible realizar el cálculo con 3 productos en lugar de 4, ya que el coste de las sumas, si consideramos las multiplicaciones como lineales, sería constante. De manera que (A+B)·( C+D) sería uno de los productos, y AC y BD los otros dos. Descripción del esquema función divide y vencerás (problema) si suficientemente simple (problema) entonces devolver solución simple (problema) sino hacer p1 … pkdescomponer (problema)

para cada pi hacer si ← divide_y_vencerás (pi) fpara

devolver combinación (s1, ..., sk) fsi ffunción

Page 115: Examenes resueltos

Estructuras de datos Para realizar el algoritmo representamos cada número en un vector de n posiciones y el resultado será de tamaño 2n, suponemos que n es potencia de 2. El algoritmo de multiplicación es para números positivos, aunque algunos valores intermedios puedan ser negativos, para los valores intermedios se considerará el vector ampliado a la posición 0 para mantener el bit de signo. Algoritmo completo a partir del refinamiento del esquema general fun multiplicar (B1[1..n], B2[1..n]de 0..1, c,f: nat) dev B[1..2n] de 0..1 var X1[0..2n], X2[0..2n], X3[0..2n], X4[0..2n], Y1[0..n], Y2[0..n] de 0..1 si c = f entonces B[1] = producto-bit(B1[c], B2[c]) sino

m = (c+f) div 2; t = m – c + 1; X1[1..2t] = multiplicar-bin (B1,B2,c,m) ; X1[0] = 0; BD X2[1..2t] = multiplicar-bin (B1,B2,m+1,f) ; X2[0] = 0; AC Y1[0..t] = restar-bin (B1[m+1..f], B1[c..m]); A-B Y2[0..t] = restar-bin (B2[c..m], B2[m+1..f]); D-C X3[0..2t] = multiplicar-bin (Y1[1..t], Y2[1..t], 1, t); (A-B)(D-C) X3[0] = (Y1[0]+Y2[0]) mod 2; X4[0..2t] = sumar-bin (X1,X2,X3) ; X4[0] = 0; AD+CB B[1..4t] = sumar-bin(desplazar(X2,2t),desplazar(X4,t),X1)

fsi ffun

Estudio del coste a = 3, b =2, k =1. ( )2log 3nΟ

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Page 116: Examenes resueltos
Page 117: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2003 – Primera semana Cuestión 1 (2 puntos). ¿Para qué se pueden utilizar montículos en el algoritmo de Kruskal? ¿Qué mejoras introduce en términos de complejidad? Cuestión 2 (1 puntos). Dado el grafo de la figura, aplicar el algoritmo de Dijkstra para hallar los caminos más cortos desde el nodo 1 hasta cada uno de los otros nodos, indicando en cada paso: nodos seleccionados, nodos no seleccionados, vector de distancias y vector de nodos precedentes.

Distancias desde 1 Nodo Precedente

PASO Nodo Seleccionado Nodo No Seleccionado 2 3 4 5 2 3 4 5

INICIO 1 2 3

Cuestión 3 (2 puntos). Se desea implementar una función para desencriptar un mensaje numérico. La función desencriptar recibe tres enteros: el mensaje cifrado c, la clave privada s y la clave pública z; y devuelve el mensaje original a. El mensaje original se recompone con la fórmula: Problema (5 puntos). Teseo se adentra en el laberinto en busca de un minotauro que no sabe dónde está. Se trata de implementar una función ariadna que le ayude a encontrar el minotauro y a salir después del laberinto. El laberinto debe representarse como una matriz de entrada a la función cuyas casillas contienen uno de los siguientes tres valores: 0 para “camino libre”, 1 para “pared” (no se puede ocupar) y 2 para “minotauro”. Teseo sale de la casilla (1,1) y debe encontrar la casilla ocupada por el minotauro. En cada punto, Teseo puede tomar la dirección Norte, Sur, Este u Oeste siempre que no haya una pared. La función ariadna debe devolver la secuencia de casillas que componen el camino de regreso desde la casilla ocupada por el minotauro hasta la casilla (1,1). La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 118: Examenes resueltos
Page 119: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2003 (Primera Semana) Cuestión 1 (2 puntos). ¿Para qué se pueden utilizar montículos en el algoritmo de Kruskal? ¿Qué mejoras introduce en términos de complejidad? (Respuesta. Fundamentos de Algo. Pag 220 y 223) Para tener en la raíz del montículo la arista más corta. Esto permite efectuar una inicialización en un tiempo ( )aΘ . Esto es ventajoso si se encuentra el árbol de recubrimiento mínimo en un momento que quede por

probar un número considerable de aristas. El algoritmo original perdería bastante tiempo ordenando aristas inútiles. Esta en ( ) a log nΘ , a es el número de aristas.

Si es un grafo denso a tiende a ( )1 / 2n n − y necesita un tiempo ( )2 n log nΘ .

Si es un grafo disperso a tiende a n y necesita un tiempo ( ) n log nΘ .

Utilizando montículos necesita un tiempo ( ) a log nΘ .

Cuestión 2 (1 puntos). Dado el grafo de la figura, aplicar el algoritmo de Dijkstra para hallar los caminos más cortos desde el nodo 1 hasta cada uno de los otros nodos, indicando en cada paso: nodos seleccionados, nodos no seleccionados, vector de distancias y vector de nodos precedentes.

Distancias desde 1 Nodo Precedente

PASO Nodo Seleccionado Nodo No Seleccionado 2 3 4 5 2 3 4 5

20 ∞ 5 7 1 1 1 1 20 12 5 7 1 4 1 1 20 12 5 7 1 4 1 1

INICIO 1 2 3

1 1,4 1,4, 5 1,4,5,3

2,3,4,5 2,3,5 2,3 2 19 12 5 7 3 4 1 1

Cuestión 3 (2 puntos). Se desea implementar una función para desencriptar un mensaje numérico. La función desencriptar recibe tres enteros: el mensaje cifrado c, la clave privada s y la clave pública z; y devuelve el mensaje original a. El mensaje original se recompone con la fórmula:

sa := c mod z Sabiendo que no se dispone del operador de potencia, implementar la función utilizando el esquema divide y vencerás. a) expoDV en Brassard, página 276.

( )( ) ( )

2

2

desencriptar (c, s, z : entero)devolver

expoDV(c,s) mod zsi s = 1 entonces dev c

si s es par entonces dev expoDV c,s

sino dev c expoDV c,

⎡ ⎤⎣ ⎦⋅ ( ) s -1

Page 120: Examenes resueltos

b) implementarlo como expomod, Brassard, página 279.

( )

( )( )

s

2

funcion desencriptar c,s,z

Calculamos c mod z

mientras i > 0 hacer

si i es impar entonces r x mod z

x x mod zi i ÷ 2

devolver r

←←

Problema (5 puntos). Teseo se adentra en el laberinto en busca de un minotauro que no sabe dónde está. Se trata de implementar una función ariadna que le ayude a encontrar el minotauro y a salir después del laberinto. El laberinto debe representarse como una matriz de entrada a la función cuyas casillas contienen uno de los siguientes tres valores: 0 para “camino libre”, 1 para “pared” (no se puede ocupar) y 2 para “minotauro”. Teseo sale de la casilla (1,1) y debe encontrar la casilla ocupada por el minotauro. En cada punto, Teseo puede tomar la dirección Norte, Sur, Este u Oeste siempre que no haya una pared. La función ariadna debe devolver la secuencia de casillas que componen el camino de regreso desde la casilla ocupada por el minotauro hasta la casilla (1,1). Solución: 5.1 Elección razonada del esquema algorítmico Como no se indica nada al respecto de la distancia entre casillas adyacentes, y ya que se sugiere utilizar únicamente una matriz, es lícito suponer que la distancia entre casillas adyacentes es siempre la misma (1, sin pérdida de generalidad). Por otra parte, no se exige hallar el camino más corto entre la entrada y el minotauro, sino que el enunciado sugiere, en todo caso, que el algoritmo tarde lo menos posible en dar una de las posibles soluciones (y ayudar a salir a Teseo cuanto antes). Tras estas consideraciones previas ya es posible elegir el esquema algorítmico más adecuado. El tablero puede verse como un grafo en el que los nodos son las casillas y en el que como máximo surgen cuatro aristas (N, S, E, O). Todas las aristas tienen el mismo valor asociado (por ejemplo, 1). En primer lugar, el algoritmo de Dijkstra queda descartado. No se pide el camino más corto y si se hiciera, las particularidades del problema hacen que el camino más corto coincida con el camino de menos nodos y, por tanto, una exploración en anchura tendrá un coste menor siempre que no se visiten nodos ya explorados, como mucho se recorrerá todo el tablero una vez (coste lineal con respecto al número de nodos versus coste cuadrático para Dijkstra). En segundo lugar, es previsible esperar que el minotauro no esté cerca de la entrada (estará en un nivel profundo del árbol de búsqueda) por lo que los posibles caminos solución serán largos. Como no es necesario encontrar el camino más corto, sino encontrar un camino lo antes posible,

Page 121: Examenes resueltos

una búsqueda en profundidad resulta más adecuada que una búsqueda en anchura. En el peor de los casos en ambas habrá que recorrer todo el tablero una vez, pero ya que buscamos un nodo profundo, se puede esperar que en media una búsqueda en profundidad requiera explorar menos nodos que una búsqueda en anchura. Si se supone que el laberinto es infinito entonces una búsqueda en profundidad no sería adecuada porque no garantiza que se pueda encontrar una solución. En este enunciado se puede presuponer que el laberinto es finito. En tercer lugar, es posible que una casilla no tenga salida por lo que es necesario habilitar un mecanismo de retroceso. Por último, es necesario que no se exploren por segunda vez casillas ya exploradas anteriormente. Por estos motivos, se ha elegido el esquema de vuelta atrás. 5.2. Descripción del esquema usado Vamos a utilizar el esquema de vuelta atrás modificado para que la búsqueda se detenga en la primera solución y para que devuelva la secuencia de ensayos que han llevado a la solución en orden inverso (es decir, la secuencia de casillas desde el minotauro hasta la salida).

fun vuelta-atrás (ensayo) dev (es_solución, solución) si válido (ensayo) entonces solución ← crear_lista(); solución ← añadir (solución, ensayo); devolver (verdadero, solución); si no hijos ← crear_lista(); hijos ← compleciones (ensayo) es_solucion ← falso;

mientras ¬ es_solución ∧ ¬ vacia (hijos) hijo ← primero (hijos)

si cumple_poda (hijo) entonces (es_solución, solución) ← vuelta-atrás(hijo) fsi fmientras si es_solución entonces solución ← añadir (solución, ensayo); fsi devolver (es_solución, solución); fsi ffun

Page 122: Examenes resueltos

5.3 Estructuras de datos Para almacenar las casillas bastará un registro de dos enteros x e y. Vamos a utilizar una lista de casillas para almacenar la solución y otra para las compleciones. Para llevar control de los nodos visitados bastará una matriz de igual tamaño que el laberinto pero de valores booleanos. Será necesario implementar las funciones de lista:

• crear_lista • vacia • añadir • primero

5.4 Algoritmo completo Suponemos “laberinto” inicializado con la configuración del laberinto y ”visitados” inicializado con todas las posiciones a falso.

tipoCasilla = registro x,y: entero;

fregistro tipoLista fun vuelta-atrás ( laberinto: vector [1..LARGO, 1..ANCHO] de entero;

casilla: tipoCasilla visitados: vector [1..LARGO, 1..ANCHO] de booleano;

) dev (es_solución: booleano; solución: tipoLista) visitados [casilla.x, casilla.y] ← verdadero; si laberinto[casilla.x, casilla.y] == 2 entonces solución ← crear_lista(); solución ← añadir (solución, casilla); devolver (verdadero, solución); si no hijos ← crear_lista(); hijos ← compleciones (laberinto, casilla) es_solución ← falso;

mientras ¬ es_solución ∧ ¬ vacia (hijos) hijo ← primero (hijos)

si ¬ visitados [hijo.x, hijo.y] entonces (es_solución, solución) ← vuelta-atrás (laberinto,hijo,visitados); fsi fmientras si es_solución entonces solución ← añadir (solución, casilla); fsi devolver (es_solución, casilla); fsi ffun

Page 123: Examenes resueltos

En el caso de encontrar al minotauro se detiene la exploración en profundidad y al deshacer las llamadas recursivas se van añadiendo a la solución las casillas que se han recorrido. Como se añaden al final de la lista, la primera será la del minotauro y la última la casilla (1,1), tal como pedía el enunciado. La función compleciones comprobará que la casilla no es una pared y que no está fuera del laberinto fun compleciones ( laberinto: vector [1..LARGO, 1..ANCHO] de entero;

casilla: tipoCasilla) dev tipoLista hijos ← crear_lista(); si casilla.x+1 <= LARGO entonces si laberinto[casilla.x+1,casilla.y] <> 1 entonces casilla_aux.x=casilla.x+1; casilla_aux.y=casilla.y; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.x-1 >= 1 entonces si laberinto[casilla.x-1,casilla.y] <> 1 entonces casilla_aux.x=casilla.x-1; casilla_aux.y=casilla.y; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.y+1 <= ANCHO entonces si laberinto[casilla.x,casilla.y+1] <> 1 entonces casilla_aux.x=casilla.x; casilla_aux.y=casilla.y+1; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.y-1 >= 1 entonces si laberinto[casilla.x,casilla.y-1] <> 1 entonces casilla_aux.x=casilla.x; casilla_aux.y=casilla.y-1; hijos ← añadir (solución, casilla_aux); fsi fsi

ffun 5.5 Estudio del coste Todas las operaciones son constantes salvo la llamada recursiva a vuelta-atrás. En cada nivel, pueden realizarse hasta 4 llamadas. Sin embargo, las llamadas no se realizan si la casilla ya ha sido visitada. Esto quiere decir que, en el caso peor, sólo se visitará una vez cada casilla. Como las operaciones para una casilla son de complejidad constante, la complejidad será O(ANCHO*LARGO), lineal con respecto al número de casillas.

Page 124: Examenes resueltos
Page 125: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2003– Segunda semana Cuestión 1 (2 puntos). Explica cómo pueden ordenarse n valores enteros positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado. Explica las ventajas e inconvenientes de este método Cuestión 2 (1 punto). ¿Puede un grafo tener dos árboles de recubrimiento mínimo diferentes? En caso afirmativo poner un ejemplo. En caso negativo justificar la respuesta. Cuestión 3 (3 puntos). Aplicar el algoritmo de planificación con plazo fijo para las actividades ia maximizando el beneficio ig en el plazo di. Detallar todos los pasos con claridad. Tarea ai 1 2 3 4 5 6 7 8 Beneficios gi 20 10 7 15 25 15 5 30 Instante di 4 5 1 1 2 3 1 2 PROBLEMA (5 puntos). Se pide diseñar completamente un algoritmo que calcule en tiempo logarítmico el valor de nf de la sucesión definida como n n-1 n-2f = af +bf con

0 1f = 0 y f = 1. Sugerencia: Pudiera ser de utilidad razonar el problema utilizando la siguiente igualdad entre matrices:

1

2 11 0n n

n n

f fa bf f

− −

⎡ ⎤ ⎡ ⎤⎡ ⎤⋅ =⎢ ⎥ ⎢ ⎥⎢ ⎥

⎣ ⎦ ⎣ ⎦ ⎣ ⎦

La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 126: Examenes resueltos
Page 127: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2003 (Segunda Semana) Cuestión 1 (2 puntos). Explica cómo pueden ordenarse n valores enteros positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado. Explica las ventajas e inconvenientes de este método. (Página 79 Brassard) Suponiendo que el rango de los valores a ordenar es limitado, es decir, sabemos que por ejemplo el rango de números a ordenar va de 0 a 2000, podemos generar un vector de 2000 elementos de tipo entero que almacenará almacenará el número de ocurrencias de cada valor de la lista a ordenar en la posición del vector correspondiente. 1- El vector esta inicializado a 0 (O(n)). 2- Recorremos la lista de valores a ordenar (O(n)). a. Por cada valor i extraído de la lista, incrementamos el valor de la posición i del vector. 3- Recorremos el vector generado mostrando los valores generados en el paso anterior (2) y omitiendo aquellas posiciones del vector que contengan un 0. Cuestión 2 (1 punto). ¿Puede un grafo tener dos árboles de recubrimiento mínimo diferentes? En caso afirmativo poner un ejemplo. En caso negativo justificar la respuesta. (Página 215 Brassard) Si. Siendo G=(N,A) un grafo conexo no dirigido en donde N es el conjunto de nodos y A es el conjunto de aristas. Suponiendo que cada arista posee una longitud no negativa. Encontrar un árbol de recubrimiento mínimo consiste en hallar un subconjunto T de las aristas de G tal que utilizando solamente las aristas de T, todos los nodos deben quedar conectados, y además la suma de las longitudes de las aristas de T debe ser tan pequeña como sea posible.

Page 128: Examenes resueltos

Cuestión 3 (3 puntos). Aplicar el algoritmo de planificación con plazo fijo para las actividades ia maximizando el beneficio ig en el plazo di. Detallar todos los pasos con claridad. Tarea ai 1 2 3 4 5 6 7 8 Beneficios gi 20 10 7 15 25 15 5 30 Instante di 4 5 1 1 2 3 1 2 Inicialmente procederemos a ordenar la matriz de costes y plazos de mayor a menor en función de los costes. Una vez realizado este paso, procederemos a aplicar el algoritmo rápido (páginas 237-241 Brassard) de planificación con plazo fijo. Resultado de la ordenación: i 1 2 3 4 5 6 7 8 Tarea ai 8 5 1 4 6 2 3 7 Beneficios gi 30 25 20 15 15 10 7 5 Instante di 2 2 4 1 3 5 1 1

Page 129: Examenes resueltos

i=2, d[2]=2. Seleccionamos K(1) i=3, d[3]=4. Seleccionamos K(4) i=4, d[4]=1. Tarea rechazada i=5, d[5]=3. Seleccionamos K(3) i=6, d[6]=5. Seleccionamos K(5) Resto de tareas rechazadas. Fin del Algoritmo. Orden de ejecución de las tareas: a5, a8, a6, a1, a2. (Página 237-241 Brassard)

Problema (5 Puntos) Se pide diseñar completamente un algoritmo que calcule en tiempo logerítmico el valor de fn de la sucesión definida como fn=afn-1+bfn-2 con f0=0 y f1=1. Sugerencia: Pudiera ser de utilidad razonar el problema utilizando la siguiente igualdad entre matrices:

=

−−

12

1

01 n

n

n

n

ff

ffba

0,1,2 3 4 5

0 3 4 5

2 1 0 0 0

1 2 3 4 5

j[]

0,1,2 3,4 5

0 3 5

2 1 0 3 0

1 2 3 4 5

j[]

0,1,2,3,4 5

0 5

2 1 5 3 0

1 2 3 4 5

j[]

0,1,2,3,4,5

0

2 1 5 3 6

1 2 3 4 5

j[]

Page 130: Examenes resueltos

Solución La solución trivial se basa en resolver recursivamente el caso n resolviendo los n términos anteriores, lo cual supondría un coste lineal que no es lo que nos piden en el enunciado del problema.

Planteamiento

Si llamamos F a la matriz

01ba

, vamos a intentar encontrar una fórmula que nos

permita expresar la solución del problema en función de los casos base que se proporcionan en el enunciado que son f0=0 y f1=1.

•==

•=

•=

•=

•=

−−

0

11

3

22

1

0

1

1

2

3

2

2

1

2

1

1

...............................

ff

Fff

Fff

ff

Fff

ff

Fff

ff

Fff

n

n

n

n

n

n

n

n

n

n

n

n

n

Con esta simplificación, es posible calcular el valor de fn con sólo calcular Fn-1 y hacer una multiplicación por el vector de casos base. La forma más eficiente de calcular exponenciaciones es mediante la técnica de divide y vencerás, aplicada sobre:

( )

==−

impar esn si

par esn si

2

21

2

2

2mod22

n

n

nndivn

FF

FFFF

Como puede observarse, reducimos el problema n a uno de n/2 que nos permite obtener una eficiencia de O(log n) frente a O(n) como ocurría si aplicábamos el algoritmo inicial.

Descripción del Esquema Algorítimico Para resolver el problema de elevar una matriz F a un determinado exponente utilizaremos la técnica de divide y vencerás aplicada a la fórmula de potencia descrita en el apartado anterior. El esquema algorítmico de divide y vencerás se basa en la idea de dividir un problema en varios subproblemas del mismo tipo cuya solución será combinada posteriormente para obtener la solución al problema inicial.

Page 131: Examenes resueltos

Como en toda función que resuelva un problema recursivamente, existirán casos umbral para los cuales la solución del problema pueda ser obtenida directamente mediante el uso de una sencilla función. En nuestro caso concreto:

1- Tamaño umbral y solución simple: En nuestro caso, para n=1 y n=0 existen soluciones triviales y, por tanto, nuestro tamaño umbral lo podemos poner en n=1.

2- Descomposición: Fn siempre lo vamos a descomponer en un único subproblema Fn/2. En este caso, el algoritmo de divide y vencerás realiza una reducción en lugar de una descomposición.

3- Combinación: La función de combinación en nuestro caso será la que hemos desarrollado al final del apartado anterior.

Estructuras de Datos. En nuestro caso utilizaremos enteros y matrices de 2x2.

Algoritmo Completo. Suponiendo que conocemos a, b, f0 y f1. fun f(n:entero) dev entero

F .

01ba

caso n=0: dev f0 n=1: dev f1 verdadero: hacer S . exp_mat(F,n-1)

s . S

0

1

ff

dev s[1] fcaso ffun fun exp_mat(M:vector[2,2]; n:entero) dev vector[2,2] si n <= 1 entonces dev solucion_simple(M,n) si no hacer p . n div 2 r . n mod 2 T . exp_mat(M,p) dev combinacion(T,r,M) fsi ffun fun combinación (T:vector[2,2]; r:entero; M:vector[2,2]) dev vector[2,2] dev TT*Mr ffun

Donde M1=M y M0=

1001

Page 132: Examenes resueltos

fun solucion_simple (M:vector[2,2], n:entero) dev vector[2,2] si n=1 dev M

si no dev

1001

fsi ffun

Estudio del Coste Función de recurrencia:

Resolución de la función de recurrencia: k=0, b=2; a=1

De acuerdo a los valores extraídos del caso particular de nuestra función, podemos concluir que la complejidad del problema solucionado será de O(log n) como nos pedían en el enunciado. (Páginas 55-59 Esquemas Algorítmicos: Enfoque Metodológico y Problemas Resueltos. J. Gonzalo Arroyo y M. Rodríguez Artacho)

( ) ( ) 1,,,0,,

n si /bn1 si

>....

=•+•<=•

=

++ bNbnRkRca

bncbnTanc

nT k

k

( )( )

( )( )

>Τ=•Τ

<Τ=

kalog

k

k

ba si nba si log

ba si

b

nnn

nT k

k

Page 133: Examenes resueltos

Programación III

Códigos de asignatura:

Sistemas: 402048; Gestión: 41204-

Nacional OriginalSeptiembre de 2003

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Prueba Presencial

Duración: 2 horasMaterial permitido: NINGUNO

Apellidos: ___________________________________________________________________________________ DNI: _______________________ Nombre: _____________________________________ Centro Asociado en el que entregó la práctica: _______________________

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico 2. Descripción del esquema usado e identificación con el problema 3. Estructuras de datos 4. Algoritmo completo a partir del refinamiento del esquema general 5. Estudio del coste

Cuestión 1 (2 puntos). Hallar el coste de los siguientes algoritmos, siendo h(n,r,k)∈O(n).

PROCEDIMIENTO uno(n,k:entero):entero;VAR i,r:entero; COMIENZO SI n<3 ENTONCES DEVOLVER(1); SINO COMIENZO r!uno(n DIV 3,k-1); ! no(n DIV 3,k+1); r r + u DEVOLVER(r); FIN FIN

PROCEDIMIENTO dos(n,k:entero):entero; VAR i,r:entero; COMIENZO SI n<4 ENTONCES DEVOLVER(1); SINO COMIENZO r ! dos(n DIV 4,k-1); r ! r + dos(n DIV 4,k+1);

PARA i! 1 HASTA n HACER COMIENZO r ! h(n,r,i) ! r + h(n,r-1,i) r FIN r ! r + dos(n DIV 4,k+2);

DEVOLVER(r); FIN FIN

Cuestión 2 (2 puntos). Una matriz T contiene n elementos. Se desea encontrar los m elementos más pequeños de T (con m<<n). Explicar cómo hacer esto de la manera más eficiente. Cuestión 3 (1 puntos). Explicar de qué manera se puede implementar mediante un esquema voraz el conocido problema de la búsqueda del camino más corto hacia la salida a un laberinto descrito por una matriz rectangular de casillas de tipos libre y ocupada, y otras dos de tipo entrada y salida. Compararlo en términos de coste con otras soluciones. Problema (5 puntos). Una operadora de telecomunicaciones dispone de 10 nodos conectados todos entre sí por una tupida red de conexiones punto a punto de fibra óptica. Cada conexión c(i,j) entre el nodo i y j ( Con i,j ∈1..10) tiene un coste asignado que sigue la fórmula c(i,j)= (i + j) MOD 8. La operadora quiere reducir gastos, para lo cual está planificando asegurar la conectividad de su red de nodos minimizando el coste. Diseñar un algoritmo que resuelva el problema (4 puntos) y aplicarlo a los datos del enunciado (1 punto).

Según el esquema elegido hay que especificar, además:

• Voraz: demostración de optimalidad • Divide y Vencerás: preorden bien fundado • Exploración en grafos: descripción del árbol de búsqueda asociado

Page 134: Examenes resueltos
Page 135: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2003(Original) Cuestión 1 (2 puntos). Hallar el coste de los siguientes algoritmos, siendo h(n,r,k) O(n)∈ .

El procedimiento uno tiene una instrucción condicional de coste constante. Dentro de la condición tiene: o bien una instrucción constante, que no tenemos en cuenta para el cálculo, o bien dos llamadas recursivas, ambas invocan la función con un tamaño n/3. //En el segundo caso de la llamada recursiva hay otra instrucción simple añadida. La expresión queda T(n) = T(n/3) + T(n/3) + 1 lo que equivale a que T(n) = 2T(n/3) + c. Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b)+cnk con k = 0, a=2 y b=3 queda que 2 > 30 y por tanto la función T(n) tiene un coste ( )3log 2O n

De forma análoga, el segundo algoritmo: está formado por una instrucción condicional de coste constante cuyo cuerpo incluye secuencialmente: (i) una llamada recursiva de tamaño n/4, //(ii) una instrucción simple, (iii) otra llama recursiva de tamaño n/4, (iv) un bucle en el que se repite n veces un cálculo consistente en llamar dos veces a una función h(n; r; i) de coste lineal, /*más una instrucción simple*/, y por último (v) una instrucción simple /* que no tenemos en cuenta para el calculo*/ y otra llamada recursiva de tamaño n/4. Sumando los términos nos sale T(n) = T(n/4) +T(n/4)+n (2n) +T(n/4), lo que equivale a T(n) = 3T(n/4) + 2n2 Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk y siendo 3 < 42 el coste es O(n2). a = 3, b = 4, k = 2

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

PROCEDIMIENTO dos (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 4 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 4, k-1); r ← r + dos (n DIV 4, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + b (n DIV 4, k+2); DEVOLVER (r); FIN FIN

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 3 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 3, k-1); r ← r + uno (n DIV 3, k+1); DEVOLVER (r); FIN FIN

Page 136: Examenes resueltos

Cuestión 2 (2 puntos). Una matriz T contiene n elementos. Se desea encontrar los m elementos más pequeños de T (con m<<n). Explicar cómo hacer esto de la manera más eficiente. Un procedimiento parcial de ordenación por selección nos da los m elementos más pequeños con coste O(m n)⋅ . Una ordenación eficiente sin embargo lo haría en O(n log n)⋅ ⋅ . Si m n≈ , el coste vendría a ser cuadrático, lo cual nos haría desechar el procedimiento de selección, sin embargo con m << n el orden O(m n)⋅ se puede considerar lineal, y en este caso el algoritmo de selección puede ser más eficiente. Cuestión 3 (1 punto). Explicar de qué manera se puede implementar mediante un esquema voraz el conocido problema de la búsqueda del camino más corto hacia la salida a un laberinto descrito por una matriz rectangular de casillas de tipos libre y ocupada, y otras dos de tipo entrada y salida. Compararlo en términos de coste con otras soluciones. Cada casilla se asimila a un nodo. Casillas libres adyacentes tendrían aristas dirigidas en ambas direcciones. El peso sería unitario para cada arista. Las casillas de tipo ocupada no tienen aristas origen ni destino. De esta forma, un algoritmo de Dijkstra puede hallar el camino más corto de un nodo llegada a todos los demás, incluyendo el nodo salida. En términos de coste, sin embargo es necesario tener en cuenta que si el laberinto es un cuadrado de lado n, el grafo tendrá 2 v = n nodos y alrededor de 2a = 4n aristas. En el análisis de coste de la resolución de Dijkstra si v (número de nodos del grafo) es lo suficientemente grande hace cierta la expresión 2a << v y por tanto podemos aproximarnos al coste O((a + v) log v)⋅ Problema (5 puntos). Una operadora de telecomunicaciones dispone de 10 nodos conectados todos entre sí por una tupida red de conexiones punto a punto de fibra óptica. Cada conexión c(i,j) entre el nodo i y j ( Con i,j 01..10) tiene un coste asignado que sigue la fórmula c(i,j) = (i + j) MOD 8. La operadora quiere reducir gastos, para lo cual está planificando asegurar la conectividad de su red de nodos minimizando el coste. Diseñar un algoritmo que resuelva el problema (4 puntos) y aplicarlo a los datos del enunciado (1 punto). Se trata de un grafo no dirigido de 10 nodos 1 2 10, ,...,n n n con una matriz simétrica de costes:

1 2 3 4 5 6 7 8 9 10 1 - 3 4 5 6 7 0 1 2 3 2 3 - 5 6 7 0 1 2 3 4 3 4 5 - 7 0 1 2 3 4 5 4 5 6 7 - 1 2 3 4 5 6 5 6 7 0 1 - 3 4 5 6 7 6 7 0 1 2 3 - 5 6 7 0 7 0 1 2 3 4 5 - 7 0 1 8 1 2 3 4 5 6 7 - 1 2 9 2 3 4 5 6 7 0 1 - 3 10 3 4 5 6 7 0 1 2 3 - Se trata de conseguir minimizar el coste de los enlaces asegurando únicamente la conectividad de la red. El enunciado describe un problema de optimización en el que se nos pide que el grafo sea conexo ("asegurar la conectividad de la red") y contenga un árbol de expansión mínimo ("que el coste sea mínimo"), ya que la conectividad se asegura no dejando subgrafos no conexos. Elección del esquema: Con las condiciones descritas podemos usar algoritmos que resuelvan el problema del árbol de expansión mínimo, dentro de la familia de los algoritmos voraces. Descripción del esquema: Se elige cualquiera de los algoritmos expuestos en el temario Kruskal o Prim, por ejemplo éste último.

Page 137: Examenes resueltos

, \

función Prim(G : grafo) :T : conjunto de aristasTB 1mientras B N hacer buscar e = u v de longitud minima tal queu B y v N BT T e

B B v

dev Tffunción

←∅←

∈ ∈

← ∪

← ∪

Hemos tomado 1 como nodo arbitrario. El conjunto B va a ir conteniendo los nodos del subgrafo ya conexo y el conjunto T irá teniendo en cada iteración aquellas aristas del árbol de expansión mínimo que contiene los nodos de B. El conjunto de candidatos es B, la condición de finalización es que B = N y la función de optimización es elegir aquella arista del subgrafo B que conecte con algún nodo de N\B con menor coste. Estructuras de datos: El grafo se representará mediante una matriz de costes. La estructura de datos tendrá un método que implementa el cálculo de la distancia entre dos nodos. En el caso de esta implementación la distancia entre dos nodos i y j es el valor de la matriz de distancias, y su coste O(1). Algoritmo completo a partir del esquema general:

función Prim(G : grafo) :T : conjunto de aristasTB 1

para i 2 hasta n hacermasProximo[i] 1distanciaMin[i] G : distancia[i; 1]

repetir n 1 vecesminpara j 2 hasta

←∅←←

←←

−←∞

\

n hacer

\* Selecciona la mejor arista entre B y N B *\

si (distanciaMin[j] 0) ^ (distanciaMin[j] < min) ent distanciaMin[k] G : distancia(j; k)m

≥←

asProximo[j] k

T T SfmasProximo[k]; kg \* Añade la arista * \distanciaMin[k] 1para j 2 hasta n hacer

si G : distancia(j; k) < distanciaMin[j] ent

←←−

distanciaMin[k] G : distancia(j; k)masProximo[j] k

dev T

←←

Page 138: Examenes resueltos

Coste: El coste del algoritmo de Prim es O(n2), que puede mejorarse utilizando una representación de montículos para el vector distanciaMin[] Optimalidad: El algoritmo de Prim encuentra la solución óptima. Se puede demostrar por inducción sobre T que añadir la arista más corta e que sale de T (Lema 6.3.1 del texto base) forma en

T e∪ un árbol de recubrimiento mínimo que contendrá al final n-1 aristas y todos los nodos del grafo G. Aplicación al problema: Tenemos los siguientes conjuntos inicialmente B = 1 y la arista mínima entre un nodo de B y otro de N\B es u = (1, 7) con valor 0. Los valores de B y la u elegida en cada momento evolucionan como sigue: B = 1,7 u = (7; 9) Coste: 0

B = 1,7,9 u = (7; 2) Coste: 1

B = 1,2,7,9 u = (2; 6) Coste: 0

B = 1,2,6,7,9 u = (6; 10) Coste: 0

B = 1,2,6,7,9,10 u = (6; 3) Coste: 1

B = 1,2,3,6,7,9,10 u = (3; 5) Coste: 0

B = 1,2,3,5,6,7,9,10 u = (6; 3) Coste: 0

B = 1,2,3,5,6,7,8,9,10 u = (9; 8) Coste: 1

B = 1,2,3,4,5,6,7,8,9,10 u = (9; 8) Coste: 1

Coste del árbol de expansión mínimo: 4

Page 139: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2003 Reserva Cuestión 1 (2 puntos). Ordenar completamente el vector en orden no decreciente por el método de Quicksort indicando claramente cual es el contenido del vector en cada paso. 3 4 5 1 3 7 6 2 Cuestión 2 (2 puntos). Con el criterio de tomar primero la moneda de mayor valor que sea menor o igual que el cambio que queda por devolver, ¿existe un algoritmo voraz para el problema de devolver el cambio con el menor número de monedas en cualquier sistema monetario? Justifique su respuesta. (Respuesta: Fundamentos de Algoritmia, pag. 211 y Esquemas algorítmicos Pág. 12). Cuestión 3 (1 puntos). ¿Se puede aplicar el procedimiento de búsqueda binaria sobre árboles con estructura de montículo? Razonar la respuesta. (Respuesta: Fundamentos de Algoritmia, pag. 255, 179, 184). Problema (5 puntos). Daniel se va de veraneo y tiene que decidir qué tesoros se lleva (el coche de hojalata, el madelman, el pañuelo de María, etc). Su madre le ha dado una bolsa de Vb cm3 con la orden expresa de que no se puede llevar nada que no quepa en la bolsa. Daniel tiene N objetos candidatos. Cada objeto i ocupa un volumen Vi y tiene un valor sentimental Si para él. Se trata de llenar la bolsa, maximizando el valor sentimental de los objetos que contiene. Evidentemente, Daniel no está dispuesto a romper en pedazos sus tesoros. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto).

Page 140: Examenes resueltos
Page 141: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2003 (Reserva) Cuestión 1 (2 puntos). Ordenar completamente el vector en orden no decreciente por el método de Quicksort indicando claramente cual es el contenido del vector en cada paso. 3 4 5 1 3 7 6 2 Solución: Tomo como pivote el primer elemento. 3 4 5 1 3 7 6 2 3 2 5 1 3 7 6 4 3 2 3 1 5 7 6 4 1 2 3 3 5 7 6 4 1 2 3 3 5 4 6 7 1 2 3 3 4 5 6 7 Cuestión 2 (2 puntos). Con el criterio de tomar primero la moneda de mayor valor que sea menor o igual que el cambio que queda por devolver, ¿existe un algoritmo voraz para el problema de devolver el cambio con el menor número de monedas en cualquier sistema monetario? Justifique su respuesta. (Respuesta: Fundamentos de Algoritmia, pag. 211 y Esquemas algorítmicos Pág. 12). No. Para aplicar el esquema voraz, el problema ha de ser de optimización. Se debe distinguir un conjunto de candidatos y que la solución pase por ir escogiéndolos o rechazándolos. La función de selección debe asegurar que la solución alcanzada es la óptima. Si no, puede que hayamos confundido el problema con uno de exploración de grafos. En el problema de las monedas, la solución es óptima tomando el conjunto de monedas españolas (cuando se utilizaban pesetas, no euros como ahora), es decir, C = 100, 25, 10 5 1. Sin embargo, si tomamos las monedas inglesas en peniques C = 30,24,12,6,3,1, para un cambio de 48 peniques, nuestro algoritmo nos daría un conjunto solución S = 30,12,6, pero la solución óptima sería S = 24,24. Cuestión 3 (1 puntos). ¿Se puede aplicar el procedimiento de búsqueda binaria sobre árboles con estructura de montículo? Razonar la respuesta. (Respuesta: Fundamentos de Algoritmia, pag. 255, 179, 184). No. El motivo es que la ordenación de los nodos es distinta, a continuación haré una breve reseña de cada uno: Procedimiento de búsqueda binaria: El vector tiene que estar ordenado totalmente, por orden no decreciente. Sea [ ]T 1..n una matriz

ordenada por orden no decreciente, tenemos [ ] [ ]≤T i T j , siempre que sea 1≤ ≤ ≤i j n . Montículo: Es un árbol binario esencialmente completo, cada nodo incluye un elemento de información denominado valor del nodo y la propiedad de que el valor de cada nodo interno es mayor o igual que los valores de sus hijos. Esto se llama propiedad de montículo. Se dice que un árbol binario es esencialmente completo si todo nodo interno, con la posible excepción de un nodo especial, tiene exactamente dos hijos. El nodo especial, si existe uno, está situado en el nivel 1 y posee un hijo izquierdo, pero no tiene hijo derecho.

Page 142: Examenes resueltos

Ejemplo de montículo: 10 7 9 4 7 5 2 2 1 6

Problema (5 puntos). Daniel se va de veraneo y tiene que decidir qué tesoros se lleva (el coche de hojalata, el madelman, el pañuelo de María, etc). Su madre le ha dado una bolsa de Vb cm3 con la orden expresa de que no se puede llevar nada que no quepa en la bolsa. Daniel tiene N objetos candidatos. Cada objeto i ocupa un volumen Vi y tiene un valor sentimental Si para él. Se trata de llenar la bolsa, maximizando el valor sentimental de los objetos que contiene. Evidentemente, Daniel no está dispuesto a romper en pedazos sus tesoros. 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema. Se trata de un problema de optimización, por lo tanto descarto divide y vencerás y vuelta atrás, ya que se exige en el enunciado que no se pueden romper los tesoros, tengo que descartar el esquema voraz ya que no se encuentra una función de selección que sea óptima para resolver el problema, se podría utilizar el esquema voraz en el casos que se pudieran trocear los tesoros, eligiéndolos por orden decreciente de vi/wi con un coste total de ( )nlognΘ . Por lo tanto elijo para resolver este problema el esquema de Ramificación y Poda. 2. Estructuras de datos. Montículo de mínimos

tipos nodo = reg sol[1..n]de 0..1 k:0..n peso, beneficio:real beneficio-opt:real prioridad freg ftipos

Page 143: Examenes resueltos

4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos).

Estudio del coste. El coste en el caso peor sería de orden exponencial, ya que en el árbol asociado al espacio de búsqueda, cada nodo tendrá dos sucesores que representarán si el objeto se añade o no a la mochila, es decir, O(2n). Sin embargo, sería de esperar que, en la práctica, el uso de la cota para podar reduzca el número de nodos que se exploran.

fun tesoros-rp(P[1..n], V[1..n]de real, M: real)dev (sol-mejor[1..n]de 0..1, beneficio-mejor:real)var X,Y: nodo,C:colapr[nodo] generamos raíz Y.k:=0; Y.peso :=0; Y.beneficio:=0; (Y.beneficio-opt,beneficio-mejor):= calculo-estimaciones(P, V, M, Y.k, Y.peso, Y.beneficio) C:= cp-vacia(); añadir(C,Y) mientras ¬es-cp-vacia?(C)^(minimo(C).beneficio-opt ≥ beneficio-mejor) hacer Y:= maximo (C); eliminar-max(C) X.k:=Y.k+1; X.sol:=Y.sol; probamos a meter el objeto en la mochila si Y.peso + P[X.k] ≤ M entonces es factible y, por tanto, las estimaciones coinciden con las de Y beneficio-opt(X) = beneficio-opt(Y) ≥ beneficio-mejor X.sol[X.k]:=1; X.peso:= Y.peso + P[X.k] X.beneficio:= Y.beneficio + V[X.k]; X.beneficio-opt := Y.beneficio-opt si X.k = n entonces beneficio(X) = beneficio-opt(X) ≥ beneficio-mejor sol-mejor:=X.sol; beneficio-mejor:= X.beneficio sino añadir(C,X) no se puede mejorar beneficio mejor fsi fsi probamos a no meter el objeto (siempre es factible) (X.beneficio-opt, pes) := calculo-estimaciones (P, V, M, X.k, Y.peso, Y.beneficio) si X.beneficio-opt ≥ beneficio-mejor entonces X.sol[X.k] := 0; X.peso := Y.peso X.beneficio := Y.beneficio si X.k = n enteonces sol-mejor := X.sol; beneficio-mejor := X.beneficio sino añadir(C,X) beneficio-mejor := max(beneficio-mejor, pes) fsi fsi fmientras ffun

fun calculo-estimaciones (P[1..n], V[1..n] de real, M: real, k: 0..n, peso, beneficio:real) dev (opt, pes: real) hueco := M-peso; pes := beneficio; opt := beneficio; j := k+1 mientras j ≤ n ^ P[j] ≤ hueco hacer podemos coger el objeto j entero hueco := hueco-P[j] opt := opt + V[j]; pes:= pes + V[j] j := j+1 ; fmientras si j ≤ n entonces quedan objetos por probar fraccionamos el objeto j (solucion voraz) opt := opt + (hueco/P[j]*V[j] extendemos a una solución en la versión 0/1 j := j+1 mientras j ≤ n ^ hueco > 0 hacer si P[j] ≤ hueco entonces hueco := hueco – P[j] pes := pes + V[j] fsi j := j+1 fmientras fsi ffun

Page 144: Examenes resueltos
Page 145: Examenes resueltos

Programación III

Códigos de asignatura:

Sistemas: 402048; Gestión: 41204-

ExtraordinarioDiciembre de 2003

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Prueba Presencial

Duración: 2 horasMaterial permitido: NINGUNO

Apellidos: ___________________________________________________________________________________ DNI: _______________________ Nombre: ______________________________ Centro donde entregó la práctica: ____________________ Especialidad: ____________

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico 2. Descripción del esquema usado e identificación con el problema 3. Estructuras de datos 4. Algoritmo completo a partir del refinamiento del esquema general 5. Estudio del coste

Cuestión 1 (2 puntos). ¿Qué significa que el tiempo de ejecución de un algoritmo está “en el orden exacto de f(n)”?. Demostrar que T(n)=5·2n+n2 está en el orden exacto de 2n. Cuestión 2 (2 punto). ¿Qué diferencias hay entre un montículo y un árbol binario de búsqueda? Cuestión 3 (2 puntos). ¿Cuáles son los casos mejor y peor para el algoritmo de ordenación rápida (Quicksort)? ¿Cuál es el orden de complejidad en cada uno de ellos? Razona tu respuesta. Problema (4 puntos). Hoy es un día duro para el taller Sleepy. Llegan las vacaciones y a las 8:00 de la mañana n clientes han pedido una revisión de su coche. Como siempre, todos necesitan que les devuelvan el coche en el menor tiempo posible. Cada coche necesita un tiempo de revisión ri y al mecánico le da lo mismo por cuál empezar: sabe que en revisar todos los coches tardará lo mismo independientemente del orden que elija. Pero al jefe de taller no le da lo mismo, la satisfacción de sus clientes es lo que importa: es mejor tener satisfechos al mayor número de ellos. Al fin y al cabo, la planificación la hace él y, evidentemente, un cliente estará más satisfecho cuanto menos tarden en devolverle el coche. Implementar un programa que decida el orden en el que revisar uno a uno los coches para maximizar la satisfacción de los clientes de Sleepy.

Page 146: Examenes resueltos
Page 147: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Diciembre 2003 Cuestión 1 (2 puntos). ¿Qué significa que el tiempo de ejecución de un algoritmo está “en el orden exacto de f(n)”?. Demostrar que ( ) 25 2nT n n= ⋅ + está en el orden exacto de 2n . Hace referencia a la notación Theta, representada por Θ , decimos que ( )t n está en Theta de ( )f n y lo denotamos como ( ) ( )( )t n f n∈Θ , si pertenece tanto a ( )( )O f n como a

( )( )f nΩ .

( )( ) ( )( ) ( )( )f n O f n f nΘ = ∩Ω REGLA DEL LÍMITE:

1. Si ( )( )n

f nlim

g n+

→∞∈ℜ , entonces ( ) ( )( )f n g n∈Θ

2. Si ( )( )

0n

f nlim

g n→∞∈ , entonces ( ) ( )( )f n O g n∈ pero ( ) ( )( )f n g n∉Θ

3. Si ( )( )n

f nlim

g n→∞∈+∞ , entonces ( ) ( )( )f n g n∈Ω pero ( ) ( )( )f n g n∉Θ

( )( )

( )( )

( )( )

( )( )

( )

22

2

3

5 2 log 2 2 5 2 log 2 25 22 2 log 2 2 log 2

5 2 log 2

n nn

n n nn n n n n

n

n

f n f n nnlim lim lim lim limg n g n

lim

→∞ →∞ →∞ →∞ →∞

→∞

′ ⋅ + ⋅ +⋅ += = = = =

( )32 log 2n5=

Por lo tanto: ( ) ( )( )f n g n∈Θ

Cuestión 2 (2 puntos). ¿Qué diferencias hay entre un montículo y un árbol binario de búsqueda? Árbol binario de búsqueda: Un árbol binario es un árbol binario de búsqueda si el valor contenido en todos los nodos internos es mayor o igual que los valores contenidos en su hijo izquierdo o en cualquiera de los descendientes de ese hijo y menor o igual que los valores contenidos en su hijo derecho o cualquiera de los descendientes de ese hijo.

20 34≤

34 35≤34 27≥

12 18≤

20 12≥

12 6≥

20

12 34

6 18 27 35

Page 148: Examenes resueltos

Montículo: Es un árbol binario esencialmente completo, cada nodo incluye un elemento de información denominado valor del nodo y la propiedad de que el valor de cada nodo interno es mayor o igual que los valores de sus hijos. Esto se llama propiedad de montículo. Se dice que un árbol binario es esencialmente completo si todo nodo interno, con la posible excepción de un nodo especial, tiene exactamente dos hijos. El nodo especial, si existe uno, está situado en el nivel 1 y posee un hijo izquierdo, pero no tiene hijo derecho. Todas las hojas se encuentran en el nivel 0 ó bien están en los niveles 0 y 1 y ninguna hoja del nivel 1 está a la izquierda de un nodo interno del mismo nivel. Ejemplo de montículo: 10 7 9 4 7 5 2 2 1 6

Cuestión 3 (1 puntos). ¿Cuáles son los casos mejor y peor para el algoritmo de ordenación rápida (Quicksort)? ¿Cual es el orden de complejidad en cada uno de ellos? Razona tu respuesta. Página 261. Si la matriz que hay que ordenar se encuentra inicialmente en orden aleatorio, entonces es probable que la mayoría de los subejemplares que haya que ordenar estén suficientemente bien equilibrados. En el caso peor si la matriz se encuentra ordenada implica una llamada recursiva a un caso de tamaño cero y otra a un caso cuyo tamaño sólo se reduce en una unidad. Para el mejor caso el orden de complejidad es ( )O nlogn .

Para el peor caso el orden de complejidad es ( )2nΩ .

Page 149: Examenes resueltos

Problema (4 puntos). Hoy es un día duro para el taller Sleepy. Llegan las vacaciones y a las 8:00 de la mañana n clientes han pedido una revisión de su coche. Como siempre, todos necesitan que les devuelvan el coche en el menor tiempo posible. Cada coche necesita un tiempo de revisión ri y al mecánico le da lo mismo por cuál empezar: sabe que en revisar todos los coches tardará lo mismo independientemente del orden que elija. Pero al jefe de taller no le da lo mismo, la satisfacción de sus clientes es lo que importa: es mejor tener satisfechos al mayor número de ellos. Al fin y al cabo, la planificación la hace él y, evidentemente, un cliente estará más satisfecho cuanto menos tarden en devolverle el coche. Implementar un programa que decida el orden en el que revisar uno a uno los coches para maximizar la satisfacción de los clientes de Sleepy. Elección razonada del esquema algorítmico más eficiente para resolver el problema. Se trata de un problema de optimización, por lo tanto descarto el esquema de divide y vencerás, para este problema se puede encontrar una función de selección que lo resuelva, de esta manera descarto el esquema de ramificación y poda, debemos elegir a los clientes por orden creciente de tiempo de finalización, este problema se corresponde con el problema de minimización del tiempo en el sistema. Esquema general: fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← seleccionar (C) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun Estructuras de datos: Tres vectores de enteros, un vector booleano y la función auxiliar ordenar índices. Algoritmo completo a partir del refinamiento del esquema general fun taller (C[1..n]nat, D[1..n]nat) dev sol[1..n] bool

var F[1..n]nat ; I[1..n]1..n ; para i=1 hasta n hacer F[i]:= C[i]+D[i]; sol[i]:= falso; fpara I:= ordenar-indices(F) sol[I[1]]:= cierto; final := F[I[1]]; para i=2 hasta n hacer si C[I[i]]≥ final entonces sol[I[i]]:= cierto; final := F[I[i]]; fsi fpara ffun fun ordenar-indices(V[1..n])dev indice [1..n]1..n merge-indice(V,indice,1,n) ffun Estudio del coste El bucle voraz es de complejidad lineal respecto al número de clientes y el orden de complejidad del algoritmo completo corresponde al de la ordenación del vector de tiempos finales ( )nlognΘ .

Page 150: Examenes resueltos
Page 151: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2004 – Primera semana Cuestión 1 (2 puntos). Programar Una función “potencia (n,m)” que halle nm, Se supone que no existe la operación potencia y que el coste de una operación de multiplicación es ( )1Ο , mediante divide y vencerás con coste en ( ) log nΘ . (Respuesta:

Cuestión 2 (1 puntos). Se tienen 4 productos infraccionables p1, p2, p3, p4 en cantidades ilimitadas cuyo beneficio es respectivamente 23, 12, 21, 11 € y cuyos pesos son respectivamente 2,4,3,5 Kgs. Tenemos un camión que carga un máximo de 55 Kgs. El problema consiste en llenar un camión con la carga de mayor valor. ¿Qué algoritmo nos permite resolver el problema? Aplicando al enunciado y detallarlo paso por paso. Cuestión 3 (2 puntos). Resolver mediante el algoritmo de Kruskal el árbol de expansión mínimo del grafo definido por la siguiente matriz de adyacencias: 1 2 3 4 5

1 . 4 5 ∞ 9 2 . . 6 ∞ 1 3 . . . 3 1 4 . . . . ∞ 5 . . . . . Problema (5 puntos). Se tiene una matriz de n x n cuyas casillas contienen valores del conjunto , ,C rojo verde amarillo= excepto una que es ‘blanco’. El único movimiento permitido consiste en que cada casilla de valor ‘blanco’ puede intercambiarse por cualesquiera de sus adyacentes no diagonales. Una solución es una tabla con una fila llena de valores iguales. Desarrollar un algoritmo que dada una matriz inicial averigüe cuantas soluciones se pueden encontrar aplicando movimientos permitidos a partir de aquella. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 152: Examenes resueltos
Page 153: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2004 (Primera Semana) Cuestión 1 (2 puntos). Programar Una función “potencia (n,m)” que halle nm, Se supone que no existe la operación potencia y que el coste de una operación de multiplicación es ( )1Ο , mediante

divide y vencerás con coste en ( ) log nΘ . (Respuesta: Fundamentos de Algoritmia, pag. 276 y EDMA 342).

Versión del Libro Estructura de datos y métodos algorítmicos fun potencia (x: numero, n: nat) dev y: numero casos n=0 → y:= 1 n=1 → y:= x n>1 ^ par(n) → entonces y:= potencia (x, n div 2); y:= y*y n>1 ^ impar(n) → entonces y:= potencia (x, n div 2); y:= x*(y*y) fcasos ffun

a = 1, b = 2, k = 0 → ( ) ( ) ( ) ( )log logkT n n n T n n∈Θ → ∈Θ

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Page 154: Examenes resueltos

Cuestión 2 (2 puntos). Se tienen 4 productos infraccionables p1, p2, p3, p4 en cantidades ilimitadas cuyo beneficio es respectivamente 23, 12, 21, 11 € y cuyos pesos son respectivamente 2,4,3,5 Kgs. Tenemos un camión que carga un máximo de 55 Kgs. El problema consiste en llenar un camión con la carga de mayor valor. ¿Qué algoritmo nos permite resolver el problema? Aplicando al enunciado y detallarlo paso por paso.

p1 p2 p3 p4 iw 2 4 3 5

iv 23 12 21 1 Ya que el enunciado impone que los productos sean infraccionables aplicaré el algoritmo de Vuelta Atrás. Lo Primero que haré ya que el algoritmo me permite ordenar los objetos en cualquier orden los ordenaré por orden decreciente de su valor/peso ya que tras hacer varias comprobaciones con más ejemplos funciona igual pero reduzco el tamaño del árbol. Quedando de la siguiente manera:

p1 p3 p2 p4 iw 2 3 4 5

iv 23 21 12 1

i iv w 11,5 7 3 0,2 Inicialmente la solución parcial está vacía, el algoritmo de vuelta atrás explora el árbol como un recorrido en profundidad, construyendo nodos y soluciones parciales a medida que avanza. Haré un pequeño gráfico. Con la siguiente notación: cada cuadro es un nodo, los números a la izquierda del punto y coma son los pesos de los objetos y los de la derecha el valor de la carga, que es lo que pretendemos optimizar. Inicio el recorrido en profundidad hasta que tengo 27 pesos con 2 que hace un total de 54, por esta rama ya no puedo continuar ya que me pasaría del peso en una unidad 56 y me exigen 55, por lo tanto retrocedo al nodo anterior y sigo la búsqueda por la siguiente rama que se corresponde con 26 pesos con 2 y 1 peso con 3 que hacen un total de 55 Kg. tal como me piden y un valor de 619 € que resulta la solución óptima para este ejemplo.

2,..,2; 598

2,..,2,3; 619

; 0

2; 23

Page 155: Examenes resueltos

Cuestión 3 (2 puntos). Resolver mediante el algoritmo de Kruskal el árbol de expansión mínimo del grafo definido por la siguiente matriz de adyacencias: (Respuesta: Fundamentos de Algoritmia, pag. 217, 218). 1 2 3 4 5 1 . 4 5 ∞ 9 2 . . 6 ∞ 1 3 . . . 3 1 4 . . . . ∞ 5 . . . . . Se ordenan las aristas de menor a mayor coste: (2,5),(3,5),(3,4),(1,2)

PASO ARISTA EVOLUCION COMPONENTES

EVOLUCION SOLUCION

INICIO 1 2 3 4

- (2,5) (3,5) (3,4) (1,2)

12345 12,534 12,3,54 12,3,4,5 1,2,3,4,5

∅ (2,5) (2,5), (3,5) (2,5), (3,5),( 3,4) (2,5), (3,5),( 3,4),( 1,2)

Proceso terminado porque sólo queda una única componente conexa

1

5

2

3

49 5 4

1

3 1 6

Page 156: Examenes resueltos

Problema (4 puntos). Se tiene una matriz de n x n cuyas casillas contienen valores del conjunto

, ,C rojo verde amarillo= excepto una que es ‘blanco’. El único movimiento permitido consiste en que cada casilla de valor ‘blanco’ puede intercambiarse por cualesquiera de sus adyacentes no diagonales. Una solución es una tabla con una fila llena de valores iguales. Desarrollar un algoritmo que dada una matriz inicial averigüe cuantas soluciones se pueden encontrar aplicando movimientos permitidos a partir de aquella. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Page 157: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2004 – Segunda semana Cuestión 1 (1 punto). ¿En qué orden está el tiempo de ejecución del siguiente algoritmo? Justifica tu respuesta.

Procedimiento h(n,i, j)si n > 0 entonces

h(n -1,i,6 - i - j);escribir i " " j;h(n -1,6 - i - j, j);

fsi;

Cuestión 2 (2 puntos). Aplica el algoritmo de Kruskal al siguiente grafo indicando claramente en cada paso qué arista se selecciona, la evolución de las componentes conexas y la evolución de la solución. Cuestión 3 (2 puntos). ¿Cuándo resulta más apropiado utilizar una exploración en anchura que en profundidad? Problema (5 puntos). Dado un grafo dirigido, finito, con ciclos y con todas las aristas de coste unitario, implementar un algoritmo que devuelva el número de nodos que contiene el camino más largo sin ciclos que se puede recorrer desde un determinado nodo. La resolución del problema debe incluir, por este orden:

1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Page 158: Examenes resueltos
Page 159: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2004 – Segunda semana Cuestión 1 (1 punto). ¿En qué orden está el tiempo de ejecución del siguiente algoritmo? Justifica tu respuesta.

Procedimiento h(n,i, j)si n > 0 entonces

h(n -1,i,6 - i - j);escribir i " " j;h(n -1,6 - i - j, j);

fsi;

kT(n)= a·T(n - b)+cn

T(n)= 2·T(n -1)+1 luego

número de llamadas: a=2 reducción por sustracción: b=1

kc·n = 1, k = 0 Aplicando la recurrencia para el caso cuando n div b na > 1 : T(n) T(a ); T(n) T(2 )∈ ∈

Cuestión 2 (2 puntos). Aplica el algoritmo de Kruskal al siguiente grafo indicando claramente en cada paso qué arista se selecciona, la evolución de las componentes conexas y la evolución de la solución.

Se ordenan las aristas de menor a mayor coste: (2,3),(4,5),(2,4),(3,5),(3,6),(2,5),(1,2),(1,3),(5,6)

PASO ARISTA EVOLUCION COMPONENTES

EVOLUCION SOLUCION

INICIO - 123456 ∅ 1 (2,3) 12,3456 (2,3) 2 (4,5) 12,34,56 (2,3),(4,5) 3 (2,4) 12,3,4,56 (2,3) ,(4,5), (2,4) 4 (3,5) Se rechaza por formar ciclo 5 (3,6) 12,3,4,5,6 (2,3), (4,5), (2,4), (3,6) 6 (2,5) Se rechaza por formar ciclo 7 (1,2) 1,2,3,4,5,6 (2,3) (4,5) (2,4) (3,6) (1,2)

Proceso terminado porque sólo queda una única componente conexa

Page 160: Examenes resueltos

Cuestión 3 (2 puntos). ¿Cuándo resulta más apropiado utilizar una exploración en anchura que en profundidad? - Cuando el grafo tiene ramas infinitas. - Cuando se busca el camino de menor número de nodos o aristas. - Cuando los nodos finales se encuentran cerca del nodo raíz. ¿En que casos puede que la exploración en anchura no encuentre solución aunque ésta exista? - Que exista una solución quiere decir que existe un camino desde el nodo inicial al nodo final. No tiene sentido, entonces, hablar de que la “solución” esté en una componente conexa diferente. Por otro lado, el caso en que un nodo genere infinitos hijos es un caso excepcional que no debería darse. Por todo ello, y salvo esta última excepción, la exploración en anchura siempre encuentra la solución, si ésta existe. ¿Y la exploración en profundidad? Razona tus respuestas. - Si existen ramas infinitas sin nodos finales puede que la exploración en profundidad quede atrapada en una de ellas y no encuentre solución aunque ésta exista. Problema (5 puntos). Dado un grafo dirigido, finito, con ciclos y con todas las aristas de coste unitario, implementar un algoritmo que devuelva el número de nodos que contiene el camino más largo sin ciclos que se puede recorrer desde un determinado nodo. Elección del esquema. Hallar el camino más largo desde un nodo en un grafo finito puede verse como un problema de determinar cuál es la profundidad máxima del árbol. Para ello, será necesario recorrer todos los caminos sin ciclos del grafo, almacenando la longitud del más largo encontrado hasta el momento. El esquema de búsqueda exhaustiva en profundidad nos permite resolver este problema. Descripción del esquema e identificación con el problema. En la página 330 del libro de texto (Brassard, 1997) se presenta el esquema de recorrido en profundidad:

procedimiento rp(nodo)nodo no ha sido visitado anteriormentevisitado[nodo] := cierto;para cada hijo en adyacentes[nodo] hacer

si visitado[nodo] = falso entoncesrp(

hijo)fsi

fpara

Page 161: Examenes resueltos

Así planteado, un nodo no se exploraría 2 veces aunque llegáramos a él desde una rama distinta. Esto es incorrecto y se debe a que el vector de nodos visitados se plantea de forma global. Veamos un ejemplo:

La exploración llega al nodo 1 y lo marca como visitado. Análogamente sigue marcando como visitados los nodos 2, 3 y 4, hallando un camino de longitud 4. Cuándo el control regresa al nodo 1 para explorar ramas alternativas, se explora el nodo 5, el 6, pero cuando llega al nodo 3, se detiene la exploración porque 3 está marcado como visitado. El nuevo camino encontrado tiene 4 nodos en vez de 5 que sería lo correcto. 6

5

4

3

2

1

Este problema lo podemos corregir si el vector de visitados tiene un ámbito local en vez de global, y se pasa una copia de padres a hijos (paso de parámetro por valor).

Estructuras de datos Necesitaremos una estructura para grafo. La más compacta y sencilla de usar es un vector en el que la componente i tiene un puntero a lista de nodos adyacentes al nodo i. Por tanto, también necesitaremos implementar una lista de nodos que puede ser, simplemente, una lista de enteros. Además, necesitaremos un vector de nodos visitados por rama. Algoritmo completo procedimiento longitud(nodo,visitados) dev long nodo no ha sido visitado anteriormente visitados[nodo]:=cierto; long_max:=0; para cada hijo en adyacentes[nodo] hacer si visitados[nodo]=falso entonces long:=longitud(hijo,visitados); si long>long_max entonces

long_max:=long fsi;

fsi fpara devolver long_max+1; La llamada inicial se realiza con el nodo inicial, y los elementos del vector de visitados inicializados a falso. Estudio del coste Sea n el número de nodos del grafo. Si suponemos un grafo denso (en el que todos los nodos están interconectados entre sí), tenemos que la longitud del camino máximo será n. Cada

Page 162: Examenes resueltos

llamada recursiva, entonces, supondrá una reducción en uno del problema. Así mismo, el número de llamadas recursivas por nivel también ira disminuyendo en uno puesto que en cada nivel hay un nodo adyacente más que ya ha sido visitado. Por último, dentro del bucle se realizan al menos n comparaciones. Por tanto, podemos establecer la siguiente recurrencia: T(n)=(n-1)·T(n-1)+n

número de llamadas: a=n-1 reducción por sustracción: b=1

c·nk=n, k=1 Aplicando la recurrencia para el caso cuando a>1: T(n)∈O(an div b); T(n)∈O(nn) Al mismo resultado se puede llegar razonando sobre la forma del árbol de exploración.

Page 163: Examenes resueltos
Page 164: Examenes resueltos
Page 165: Examenes resueltos

[ ]( )

( )

( )( )

Proc crear_monticulo T 1..n ,i

si i > ndevuelve T

sinoflotar i,T

crear_monticulo T,i+1fsi

fproc

[ ]( )

( ) [ ] [ ][ ] [ ]( )

( )

,

,

Proc Flotar i T 1...n ;

i_padre := i div 2;Si i > 1 y T i T i_padre entonces

Intercambiar T i T i_padre ;

Flotar i_padre,T ;fFlotar;

>

RESPUESTAS EXAMEN Programación III. Septiembre 2004 (Original) Cuestión 1 (2 puntos). ¿Qué significa que el tiempo de ejecución de un algoritmo está “en el orden exacto de f(n)”? Demostrar que 3 2T(n)= n +9·n ·log(n) está en el orden exacto de 3n . La definición formal es (f(n)) = O(f(n)) (f(n)) Θ ∩Ω , y considerando que si

( )( )n

f nlim

g n+

→∞∈ℜ , entonces ( ) ( )( )f n g n∈Θ

según la relación del apartado 3.3 (Ver p. 100 del texto base) y además aplicamos el teorema de L´Hopital (p. 38) obtenemos que:

( )( )

( )( )n n

f n f nlim lim

g n g n→∞ →∞

′=

′ con lo que:

( )( )( )

2

2

3 18 9 6 18 27 6 18 /3 6 6

6 18

3 2

3n n n n n

n

f n n +9·n ·log(n) n + ·n·log(n) n n+ ·log(n) + n lim lim lim lim limg n n n n

n+lim

→∞ →∞ →∞ →∞ →∞

→∞

+ += = = = =

=( )6 18

16 6n

n n+lim

n→∞= =

con lo que ( )33 2n +9·n ·log(n) n∈Θ También será válido hallar las constantes c y d según la definición de la notación Theta (p.100) Cuestión 2 (2 puntos). Implementar una versión recursiva de una función que tome un vector y le dé estructura de montículo. La llamada inicial será ( )_ ,2crear monticulo T . Otra versión pero en este caso sin usar funciones auxiliares es sustituir el código de flotar por su versión iterativa e insertarlo en la función anterior.

Page 166: Examenes resueltos

Cuestión 3 (2 puntos).¿En qué se diferencian los algoritmos de Prim y de Kruskal? Discute tanto los algoritmos como su complejidad en los casos peores de cada uno. En primer lugar difieren en la forma de crear el camino mínimo. En el caso de Prim la solución es siempre un ARM y en el otro caso, lo son las componentes conexas pero sin referencia al grafo inicial, salvo al final del mismo. En segundo lugar en términos de coste, el algoritmo de Kruskal requiere un tiempo que está en

(a· logn) Θ con a el número de aristas, por lo que en el caso peor si el grafo es denso y a se acerca a 2n , entonces es menos eficiente que el de Prim que es cuadrático, ocurriendo lo contrario para grafos dispersos. PROBLEMA (5 puntos). Sean dos vectores de caracteres. El primero se denomina texto y el segundo consulta, siendo éste de igual o menor longitud que el primero. Al vector consulta se le pueden aplicar, cuantas veces sea necesario, los siguientes tres tipos de operaciones, que añaden cada una un coste diferente a la edición de la consulta: • Intercambio de dos caracteres consecutivos: coste de edición igual a 1 • Sustitución de un carácter por otro cualquiera: coste de edición igual a 2 • Inserción de un carácter cualquiera en una posición cualquiera: coste de edición igual a 3 Implementar una función que escriba la secuencia de operaciones con menor coste total que hay que realizar sobre el vector consulta para que coincida exactamente con el vector texto. La

Page 167: Examenes resueltos

función devolverá el coste total de estas operaciones, es decir, la suma de los costes asociados a cada operación realizada. 1. Elección razonada del esquema algorítmico La solución es resultado de una secuencia de pasos o decisiones pero no se puede establecer un criterio óptimo de selección de cada decisión por lo que no puede ser un esquema voraz. Por tanto hay que realizar una exploración de las posibles soluciones y buscar la óptima. Debido a que hay un criterio de optimalidad, es decir, existe una función que decide si un nodo puede llevar a una solución mejor que la encontrada hasta el momento, el esquema adecuado es Ramificación y Poda. 2. Descripción del esquema Función RamificaciónPoda (nodo_raíz) dev nodo inicializarSolución(Solución,valor_sol_actual); Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si es_mejor(cota, valor_sol_actual) entonces si válido(nodo) entonces /*cota es el valor real de la mejor solución hasta ahora*/ valor_sol_actual:=cota; Solución:=nodo; fsi; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; sino devolver Solución fsi; /*termina el bucle, montículo no tiene mejores*/ fmientras devolver Solución; 3. Estructuras de datos

• Vector de texto • Vector de consulta • Montículo de mínimos en el que cada componente almacene una solución parcial (nodo)

con su cota correspondiente. • nodo=tupla

acciones: lista de Strings; último_coincidente: cardinal; long: cardinal; coste: cardinal; 4. Algoritmo completo inicializarSolución

Page 168: Examenes resueltos

La solución inicial debe tener un coste asociado mayor o igual que la solución final. De acuerdo con el problema, basta con realizar sustituciones de los caracteres de la consulta (coste=2*long_consulta) y realizar la inserción de los caracteres que faltan (coste=3*(long_texto-long_consulta)). Además tenemos que construir la solución inicial: la secuencia de sustituciones e inserciones. Función inicializarSolución(long_consulta, texto, long_texto, Solución, valor_sol_actual); valor_sol_actual:= 2*long_consulta+3*(long_texto-long_consulta); Solución:=listaVacia(); para i desde 1 hasta long_consulta hacer añadir(Solución, “sustituir i por texto[i]”); fpara; para i desde long_consulta+1 hasta long_texto hacer añadir(Solución, “insertar en i, texto[i]”); fpara;

válido(nodo) Un nodo será válido (como solución) si se han hecho coincidir los long_texto caracteres de texto. Para ello, vamos a ir haciendo coincidir la solución desde el principio del vector hasta el final. por tanto, un nodo será válido (aunque no sea la mejor solución todavía) si:

nodo.último_coincidente==long_texto es_mejor(cota, valor_sol_actual)

Como se trata de encontrar la solución de menor coste, una cota será mejor que el valor de la solución actual si:

cota<valor_sol_actual

acotar(nodo) Se trata de realizar una estimación que sea mejor o igual que la mejor solución que se puede alcanzar desde ese nodo. De esta manera sabremos que si, aún así, la estimación es peor que la solución actual, por esa rama no encontraremos nada mejor y se puede podar. La mejor estimación será sumar al coste ya acumulado, el menor coste que podría tener completar la solución: que el resto de caracteres de consulta coincidieran (coste=0) y realizar tantas inserciones como caracteres nos falten (coste=2*(long_texto-nodo.long)). Es decir, acotar(nodo) es: nodo.coste+2*(long_texto-nodo.long)

compleciones(nodo)

Sabiendo que hasta nodo.último_coincidente todos los caracteres coinciden, se trata de considerar las posibilidades para que el siguiente carácter de la consulta coincida con el texto:

• No hacer nada si ya coinciden de antemano. • Intercambiarlo por el siguiente si éste coincide con el texto. • Sustituirlo por el correspondiente del texto • Insertar el correspondiente del texto y correr el resto del vector, siempre que

la consulta no haya alcanzado el tamaño del texto. Si se da el primer caso, no es necesario generar el resto de compleciones porque no se puede encontrar una solución mejor con ninguna de las otras alternativas. Aún así, no pasaría nada si se incluyen. Sin embargo, para el resto de alternativas, no hay garantías

Page 169: Examenes resueltos

de que una permita encontrar mejor solución que otra, aunque el coste de la acción puntual sea menor. Por tanto, hay que incluir todas las alternativas. Función compleciones(nodo, texto, long_texto, consulta) dev lista_nodos lista:=crearLista(); si consulta[hijo.último_coincidente]==texto[hijo.último_coincidente] entonces

hijo:=crearNodo(); hijo.último_coincidente:=nodo.último_coincidente+1;

hijo.acciones=nodo.acciones; hijo.coste=nodo.coste;

hijo.long=nodo.long; añadir(lista, hijo); si no

/* intercambio */ si consulta[hijo.último_coincidente+1]==texto[hijo.último_coincidente] entonces intercambiar(consulta[hijo.último_coincidente],

consulta[hijo.último_coincidente+1]); hijo:=crearNodo();

hijo.último_coincidente:=nodo.último_coincidente+1; hijo.acciones=nodo.acciones;

añadir(hijo.acciones,”intercambiar consulta[hijo.último_coincidente] por consulta[hijo.último_coincidente+1]”);

hijo.coste=nodo.coste+1; hijo.long=nodo.long; añadir(lista, hijo);

fsi; /* sustitución */

hijo:=crearNodo(); hijo.último_coincidente:=nodo.último_coincidente+1;

hijo.acciones=nodo.acciones; insertar(hijo.acciones,”sustituir hijo.último_coincidente por

texto[hijo.último_coincidente]”); hijo.coste=nodo.coste+2;

hijo.long=nodo.long; añadir(lista, hijo); /* inserción */ si (nodo.long<long_texto) entonces

hijo:=crearNodo(); hijo.último_coincidente:=nodo.último_coincidente+1;

hijo.acciones=nodo.acciones; insertar(hijo.acciones,”insertar en hijo.último_coincidente,

texto[hijo.último_coincidente]”); hijo.coste=nodo.coste+3;

hijo.long=nodo.long+1; añadir(lista, hijo); fsi; fsi; devolver lista;

Page 170: Examenes resueltos

La función principal quedaría entonces como sigue: Función ajustar(consulta, long_consulta, texto, long_texto) dev coste

inicializarSolución(long_consulta, texto, long_texto, Solución, valor_sol_actual); Montículo:=montículoVacío(); nodo.acciones=listaVacia(); nodo.último_coincidente=0; nodo.coste=0; nodo.long=long_consulta; cota:= nodo.coste+2*(long_texto-nodo.long); poner((cota,nodo),Montículo); mientras ¬vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si cota<valor_sol_actual entonces si nodo.último_coincidente==long_texto entonces valor_sol_actual:=cota; solución:=nodo.acciones; si no

para cada hijo en compleciones(nodo, texto, long_texto, consulta) hacer

cota:= nodo.coste+2*(long_texto-nodo.long); poner((cota,hijo),Montículo);

fpara; fsi;

sino /* Ya no puede haber una solución mejor */ escribir(solución);

devolver valor_sol_actual; fsi;

fmientras escribir(solucion); devolver valor_sol_actual; 5. Estudio del coste En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan 3 hijos por nodo hasta llegar a una profundidad de long_texto. Por tanto, el espacio a recorrer siempre será menor que 3long_texto.

Page 171: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2004 Reserva Cuestión 1 (2 puntos). Defina qué es un árbol de recubrimiento mínimo, explique alguno de los algoritmos propuestos en la asignatura para hallarlos, aplicándolo paso a paso a un ejemplo. (Respuesta: Fundamentos de Algoritmia, pags. 215-223). Cuestión 2 (2 puntos). Sea [ ]1..12T una matriz tal que [ ]T i i= para todo i 12≤ .Crear un montículo en tiempo lineal, especificando claramente cada paso y mostrando en todo momento el estado de la matriz T. (Respuesta: Fundamentos de Algoritmia, pag. 189). Cuestión 3 (2 puntos). Se dispone de n productos diferentes, infraccionables y en cantidades ilimitadas. Cada tipo de producto tiene asociado un peso y un beneficio concreto. Deseamos cargar un camión, que puede transportar un peso máximo PMAX, maximizando el beneficio de los productos transportados por este. ¿Sería posible aplicar un algoritmo voraz a este planteamiento? Responder razonadamente y plantear un ejemplo que justifique la respuesta. (Respuesta: Fundamentos de Algoritmia, Págs. 227, 343, 353). PROBLEMA (5 puntos). Sea una red de compartición de ficheros, similar a las que actualmente se utilizan para intercambiar globalmente archivos por internet. Esta red se encuentra formada por n servidores, siendo todos ellos capaces de distribuir un número n de archivos, de tamaño Ti Kilobytes, a diferentes velocidades de transmisión. La velocidad de transmisión de datos de cada uno de los servidores viene determinada por una tabla de velocidades de transmisión S, donde, Sij es la velocidad de transmisión del servidor i para el archivo j (en K/seg). Se pide diseñar un algoritmo capaz de repartir la descarga de los n archivos entre los n servidores disponibles, minimizando el tiempo global de descarga de todos los archivos. La función deberá indicar el tiempo óptimo de descarga, así como los servidores desde los que serán descargados los n archivos. Suponga que la descargase lleva a cabo de manera secuencial, lo que significa que no es posible descargar más de un archivo al mismo tiempo. Tome como ejemplo ilustrativo de los datos de entrada una red de compartición de 3 ficheros (A1, A2, A3) en 3 servidores diferentes (S1, S2, S3). El tamaño de los 3 ficheros es T1=100K, T2=200K, T3=300K y la velocidad de transmisión de los 3 servidores viene dado por la matriz:

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Page 172: Examenes resueltos
Page 173: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2004 (Reserva) Cuestión 1 (2 puntos). Defina qué es un árbol de recubrimiento mínimo, explique alguno de los algoritmos propuestos en la asignatura para hallarlos, aplicándolo paso a paso a un ejemplo. (Respuesta: Fundamentos de Algoritmia, pags. 215-223). Dado un grafo, debemos obtener un nuevo grafo que sólo contenga las aristas imprescindibles para que todos los nodos queden conectados y la suma de las longitudes de las aristas de del nuevo grafo debe ser tan pequeña como sea posible, se aplica a problemas que tienen que ver con distribuciones geográficas Hay dos algoritmos que podemos utilizar para resolver este tipo de problemas: Kruskal y Prim. KRUSKAL: Partimos del conjunto de aristas T que inicialmente está vacío, se selecciona en cada paso la arista de menor etiqueta que no provoque ciclo, es decir en orden creciente de longitud de sus aristas. El algoritmo se detiene cuando solo queda una componente conexa. Se ordenan las aristas de menor a mayor coste:

PASO ARISTA EVOLUCION COMPONENTES

EVOLUCION SOLUCION

INICIO 1 2 3 4 5 6 7

- (1,2) (2,3) (4,5) (6,7) (1,4) (2,5) (4,7)

1234567 1,234567 1,2,34567 1,2,34,567 1,2,34,56,7 1,2,3,4,56,7 Se rechaza porque los extremos

1,2,3,4,5,6,7

∅ (1,2) (1,2), (2,3) (1,2), (2,3),( 4,5) (1,2), (2,3),( 4,5),( 6,7) (1,2), (2,3),( 4,5),( 6,7),( 1,4) de la arista ya están en la misma comp. conexa

(1,2), (2,3),( 4,5),( 6,7),( 1,4),( 4,7)

PRIM: En este algoritmo el árbol de recubrimiento mínimo crece de forma natural, comenzando por una raíz arbitraria, en cada fase se añade una nueva rama al árbol construido con el valor más pequeño posible, el árbol se detiene cuando se han alcanzado todos los nodos.

PASO ARISTA EVOLUCION COMPONENTES EVOLUCION SOLUCION

INICIO 1 2 3 4 5 6

- (1,2) (2,3) (1,4) (4,5) (4,7) (7,6)

1 1,2 1,2,3 1,2,3,4 1,2,3,4,5 1,2,3,4,5,7 1,2,3,4,5,6,7

∅ (1,2) (1,2), (2,3) (1,2), (2,3),(1,4) (1,2), (2,3),(1,4),(4,5) (1,2), (2,3),(1,4),(4,5),(4,7) (1,2), (2,3),(1,4),(4,5),(4,7),(7,6)

Estos algoritmos difieren en la forma de crear el camino mínimo. En el caso de Prim la solución es siempre un AEM y en el otro caso, lo son las componentes conexas pero sin referencia al grafo inicial, salvo al final del mismo. En segundo lugar en términos de coste, el algoritmo de Kruskal requiere un tiempo que está en

(a logn) Θ ⋅ con a el número de aristas, por lo que en el caso peor si el grafo es denso y a se tiende a

( )n n -1 2 , con un tiempo que está en ( )2n lognΘ entonces es menos eficiente que el de Prim que es cuadrático, para un grafo disperso a tiende a n por lo que Kruskal requiere un tiempo que está en ( )nlognΘ y el algoritmo de Prim es menos eficiente en este caso. Los dos algoritmos se pueden

implementar con montículos, en este caso los dos algoritmos están en ( )a lognΘ ⋅

Page 174: Examenes resueltos

Proc Flotar(T[1...n],i)k iRepetirj k

Si j > 1 y T[j 2] T[k] entonces k j 2

Intercambiar T[j] y T[k]Hasta j = k

Fproc

←÷ >

← ÷

Proc añadir - nodo (T[1...12],v)Añade un elemento cuyo vlor es v al final

del montículo T[1...n]T[n+1] vFlotar(T[1...n+1],n+1)

Fproc

Cuestión 2 (2 puntos). Sea [ ]1..12T una matriz tal que [ ]T i i= para todo i 12≤ .Crear un montículo en tiempo lineal, especificando claramente cada paso y mostrando en todo momento el estado de la matriz T. (Respuesta: Fundamentos de Algoritmia, pag. 189). Para Crear un montículo Se inserta un nuevo elemento al final del montículo (primera posición libre) Si se mantiene la propiedad del montículo no hay que hacer ninguna operación Si no se mantiene la propiedad del montículo hay que restaurarla Se restaura la propiedad del montículo intercambiando el nuevo elemento con su padre cuantas veces sea necesario, a esta operación de subir en el montículo se la denomina flotar un elemento El nuevo elemento sube en el montículo (flota) y sus padres bajan en el montículo (se hunden) A la operación de bajar en un montículo se la denomina hundir Por ejemplo con el vector T [15,11,12,20,5,16,8,32,18,31,25,14] Detallo paso por paso:

1- Inserto el elemento 15. Estado de la matriz T [15]. 2- Inserto el elemento 11 y llamo al procedimiento flotar. Estado de la matriz T [11, 15]. 3- Inserto el elemento 12. Estado de la matriz T [11, 15,12]. 4- Inserto el elemento 20. Estado de la matriz T [11, 15,12,20]. 5- Inserto el elemento 5 y llamo al procedimiento flotar dos veces. Estado de la matriz T [5,11,

12,20,15]. 6- Inserto el elemento 16. Estado de la matriz T [5,11, 12,20,15,16]. 7- Inserto el elemento 8 y llamo al procedimiento flotar. Estado de la matriz T [5,11, 12,20,15,16,8]. 8- Inserto el elemento 32. Estado de la matriz T [5,11, 12,20,15,16,8,32]. 9- Inserto el elemento 18 y llamo al procedimiento flotar. Estado de la matriz T [5,11,

12,18,15,16,8,32,20]. 10- Inserto el elemento 31. Estado de la matriz T [5,11, 12,18,15,16,8,32,20,31]. 11- Inserto el elemento 25. Estado de la matriz T [5,11, 12,18,15,16,8,32,20,31,25]. 12- Inserto el elemento 14 y llamo al procedimiento flotar. Estado de la matriz T [5,11,

12,18,15,14,8,32,20,31,25,16]. Después de realizar estas operaciones se puede observar que el vector tiene estructura de montículo de mínimos.

Page 175: Examenes resueltos

Cuestión 3 (2 puntos). Se dispone de n productos diferentes, infraccionables y en cantidades ilimitadas. Cada tipo de producto tiene asociado un peso y un beneficio concreto. Deseamos cargar un camión, que puede transportar un peso máximo PMAX, maximizando el beneficio de los productos transportados por este. ¿Sería posible aplicar un algoritmo voraz a este planteamiento? Responder razonadamente y plantear un ejemplo que justifique la respuesta. (Respuesta: Fundamentos de Algoritmia, Págs. 227, 343, 353). NO. La variante del problema de la mochila que admite solución voraz es la variante continua, donde podemos fragmentar los objetos. Esta variante admite solución voraz porque encontramos una función de selección que nos permite escoger del candidato a cada paso de forma que obtengamos una solución óptima. Dicha función consiste en escoger los objetos por orden decreciente (de mayor a menor) según su relación valor/peso, lo que nos lleva a una solución óptima. La variante que no admite solución óptima es la que no nos permite fragmentar los objetos, veamos esto con un ejemplo. Dada la siguiente relación de objetos valor-peso para una mochila de capacidad 10 (W=10, peso máximo de la mochila) .

a b c iw 6 5 5

iv 8 5 5 Según el algoritmo voraz de la variante continua tomaríamos los objetos según su orden decreciente en función de la relación valor/peso. De este modo tendríamos: a (vi/wi = 1,333) , b (vi/wi= 1) y c(vi/wi=1) . La sucesión a, b y c. Sin embargo como en esta ocasión NO podemos fragmentar los objetos al introducir en la mochila el objeto a de peso 6 ya no podemos introducir ninguno más, el valor conseguido será entonces de 8; mientras que si introducimos primero el objeto b, queda aún espacio para el objeto c, con lo que en esta ocasión hemos utilizado el peso total máximo de la mochila y el valor conseguido es de 10. Siendo esta la solución óptima. Vemos con este ejemplo como el criterio seguido en la variante continua del problema no puede aplicarse en el caso en el que los objetos no puedan fragmentarse. PROBLEMA (5 puntos). Sea una red de compartición de ficheros, similar a las que actualmente se utilizan para intercambiar globalmente archivos por internet. Esta red se encuentra formada por n servidores, siendo todos ellos capaces de distribuir un número n de archivos, de tamaño Ti Kilobytes, a diferentes velocidades de transmisión. La velocidad de transmisión de datos de cada uno de los servidores viene determinada por una tabla de velocidades de transmisión S, donde, Sij es la velocidad de transmisión del servidor i para el archivo j (en K/seg). Se pide diseñar un algoritmo capaz de repartir la descarga de los n archivos entre los n servidores disponibles, minimizando el tiempo global de descarga de todos los archivos. La función deberá indicar el tiempo óptimo de descarga, así como los servidores desde los que serán descargados los n archivos. Suponga que la descargase lleva a cabo de manera secuencial, lo que significa que no es posible descargar más de un archivo al mismo tiempo. Tome como ejemplo ilustrativo de los datos de entrada una red de compartición de 3 ficheros (A1, A2, A3) en 3 servidores diferentes (S1, S2, S3). El tamaño de los 3 ficheros es T1=100K, T2=200K, T3=300K y la velocidad de transmisión de los 3 servidores viene dado por la matriz:

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. 2. Descripción del esquema usado e identificación con el problema. 3. Estructuras de datos. 4. Algoritmo completo a partir del refinamiento del esquema general. 5. Estudio del coste.

Page 176: Examenes resueltos

Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias. nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; filas_no_asignadas: lista de cardinal; coste: cardinal; Montículo de mínimos (cota mejor la de menor coste) Desarrollar el algoritmo completo. Las funciones generales del esquema general que hay que instanciar son: 1. a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) 2. b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” 3. c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores posibles para asignaciones[último_asignado+1]) 4. Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0; nodo.coste=0; cota:=acotar(nodo,costes); poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras

devolver ∅;

Page 177: Examenes resueltos

Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer minimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota; Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista; Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 178: Examenes resueltos
Page 179: Examenes resueltos
Page 180: Examenes resueltos
Page 181: Examenes resueltos

Programación III

Códigos de asignatura:

Sistemas: 402048; Gestión: 41204-

Primera SemanaFebrero 2005

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Prueba Presencial

Duración: 2 horasMaterial permitido: NINGUNO

Apellidos: ___________________________________________________________________________________ DNI: _______________________ Nombre: _____________________________________ Centro Asociado en el que entregó la práctica: _______________________

Cuestión 1 (2 puntos). Se dispone de un conjunto de ficheros f1, f2, ..., fn con tamaños I1, I2, ..., In y de un disquete con una capacidad total de almacenamiento de d<I1+I2+...+In. a) Suponiendo que se desea maximizar el número de ficheros almacenados y que se hace uso de un planteamiento voraz basado en la selección de ficheros de menor a mayor tamaño, ¿el algoritmo propuesto siempre obtendría la solución óptima?. En caso afirmativo demostrar la optimalidad y en caso negativo ponga un contraejemplo; b) En caso de que quisiéramos ocupar la mayor cantidad de espacio en el disquete independientemente del número de ficheros almacenados, ¿una estrategia voraz basada en la selección de ficheros de mayor a menor tamaño obtendría en todos los casos la solución óptima?. En caso afirmativo demuestre la optimalidad, en caso negativo ponga un contraejemplo. Solución: Apartado A El algoritmo voraz obtendría la solución óptima, es decir, un disquete con el mayor número posible de ficheros. Demostración: Suponiendo que los programas se encuentran inicialmente ordenados de menor a mayor tamaño, vamos a demostrar la optimalidad de la solución comparando una solución óptima con una solución obtenida por el algoritmo voraz. Si ambas soluciones no fueran iguales, iremos transformando la solución óptima de partida, de forma que continúe siendo óptima, pero asemejándola cada vez más con la obtenida por el algoritmo voraz. Si consiguiéramos igualar ambas soluciones en un número finito de pasos, entonces podremos afirmar que la solución obtenida por el algoritmo es óptima.

Notación: Una solución cualquiera viene representada por Z=(z1, z2, ..., zn) donde zi=0 implica que el fichero fi no ha sido seleccionado como parte de la

solución. De este modo, ∑=

n

iiz

1

indicará el número de ficheros seleccionados

como solución al problema. Siendo X la solución devuelta por la estrategia voraz e Y la solución óptima al problema. Supongamos que la estrategia voraz propuesta selecciona los k primeros ficheros (con 1 = k = n), recordamos que los ficheros se encuentran inicialmente ordenados de menor a mayor tamaño. El fichero k+1 es rechazado puesto que ya no es posible incluir un solo fichero más. De este modo, la solución X será (x1, x2, ..., xk,..., xn), donde 1...1 =.. ixki y

0...1 =+.. ixnki . Comenzando a comparar X con Y de izquierda a derecha, supongamos que j = 1 sea la primera posición donde xj . yj . En este caso, obligatoriamente j = k ya que en caso contrario la solución óptima incluiría todos los ficheros escogidos por la estrategia voraz y alguno más, lo que se contradice con el hecho de que los ficheros del k+1 al n se rechazan por la estrategia voraz porque no caben.

Este modo, xj . yj implica que yi=0, por lo que 11

−=∑=

jyj

ii , que es menor que el número de ficheros seleccionados

por nuestra estrategia voraz como solución al problema jxj

ii =∑

=1

. Como suponemos que Y es una solución óptima,

Page 182: Examenes resueltos

kxyn

ii

n

ii ==∑∑

== 11

, esto significa que existe un l > k = j tal que yl = 1, es decir, existe un fichero posterior para

compensar el que no se ha cogido antes. Por la ordenación impuesta a los ficheros, sabemos que lj = ll, es decir, que si fl cabe en el disco, podemos poner en su lugar fj sin sobrepasar la capacidad total. Realizando este cambio en la solución óptima Y, obtenemos otra solución Y’ en la cual y’j= 1 = xj, y’l=0 y para el resto y’i = yi. Esta nueva solución es más parecida a X, y tiene el mismo número de ficheros que Y’, por lo que sigue siendo óptima. Repitiendo este proceso, podemos ir igualando los ficheros en la solución óptima a los de la solución voraz X, hasta alcanzar la posición k. Apartado B El algoritmo voraz no obtendría la solución óptima en todos los casos. Contraejemplo: Supongamos la siguiente lista de ficheros con tamaños asociados:

Fichero F1 F2 F3 Tamaño 40 30 15

Supongamos que la capacidad máxima del disquete es 45. Aplicando la estrategia voraz propuesta, únicamente podríamos almacenar el fichero F1, ocupando 40 de los 45 de capacidad que tiene el disquete. Sin embargo, si hubiéramos seleccionado los ficheros F2 y F3 hubiera sido posible maximizar el espacio ocupado en el disco. Cuestión 2 (2 punto). Exponga y explique el algoritmo más eficiente que conozca para realizar una planificación de tareas con plazo fijo maximizando el beneficio. Dada la tabla adjunta de tareas con sus beneficios (gi) y caducidades (di) asociados. Aplique paso a paso el algoritmo propuesto, suponiendo que se desea realizar una planificación en un tiempo t=5.

i 1 2 3 4 5 6 7 8 9 gi 30 10 2 11 10 9 2 56 33 di 5 3 2 2 1 2 7 5 4

Solución: Apartado A El algoritmo más apropiado es el algoritmo secuencia2 explicado y desarrollado en pg 240-241 del texto base y que ha sido utilizado en la práctica (Bloque 1). El alumno debe haberlo expuesto y explicado. Apartado B

1. Inicialmente ordenamos la tabla propuesta por orden decreciente de beneficios. 2. Creamos el número apropiado de estructuras de partición. p=min(9,max(di))=min(9,7)=7. Como en este

caso concreto queremos únicamente planificar las 5 primeras tareas p puede reducirse a 5. 3. Vamos extrayendo cada una de las tareas por orden decreciente de beneficios e incluyéndolas en su

correspondiente estructura de partición. Esta operación implica fusionar la estructura en la cual se ha incluido la tarea con la estructura de partición inmediatamente anterior.

4. El algoritmo termina cuando ya no queda ninguna estructura de partición libre para asignar tarea.

i 8 9 1 4 5 2 6 3 7 gi 56 33 30 11 10 10 9 2 2 di 5 4 5 2 1 3 2 2 7

Tabla de costes y caducidades ordenada

Page 183: Examenes resueltos

El proceso puede esquematizarse del siguiente modo:

0

0

1

1

2

2

3

3

4

4

5

5 0 1 2 3 4Res[]

0

0

1

1

2

2

3

3

4

4

5

80 1 2 3 4

Res[]

Selecciono tarea 8

0

0

1

1

2

2

3

3

4

5

9 80 1 2 3 4

Res[]

Selecciono tarea 9

0

0

1

1

2

2

3

4

5

1 9 80 1 2 3 4

Res[]

Selecciono tarea 1

0

0

1

1

2

3

4

5

4 1 9 80 1 2 3 4

Res[]

Selecciono tarea 4

Page 184: Examenes resueltos

Cuestión 3 (1 puntos). Explique las diferencias entre un recorrido en anchura y un recorrido en profundidad. Exponga un algoritmo iterativo para cada uno de los recorridos explicando las estructuras de datos asociadas, así como su coste. Solución págs 338 y 339. Solución: procedimiento ra (v) Q ← cola-vacía marca[v] ← visitado poner v en Q mientras Q no esté vacía hacer u ← primero (Q) quitar u de Q para cada nodo w adyacente a u hacer si marca [w]≠ visitado entonces marca [w] ← visitado poner w en Q procedimiento rp2 (v) P ← pila-vacía marca[v] ← visitado; apilar v en P mientras P no esté vacía hacer mientras exista un nodo w adyacente a cima (P) tal que marca [w]≠ visitado hacer marca [w] ← visitado apilar w en P w es la nueva cima (P) desapilar P El procedimiento de inicialización y arranque será: procedimiento recorrido (G) para cada v 0 N hacer marca[v] ← no visitado para cada v 0 N hacer si marca[v]≠ visitado entonces rp2 o ra (v) El recorrido en anchura utiliza como estructura de datos una cola y el recorrido en profundidad una pila, el coste de ambas está en Θ(max(a,n))

Page 185: Examenes resueltos

Problema (5 puntos). Partiendo de un conjunto N=n1, n2, ..., nm compuesto por m número positivos y de un conjunto O=+,-,*,/ con las operaciones aritméticas básicas, se pide obtener una secuencia de operaciones factible para conseguir un número objetivo P. Como restricciones al problema, debe tenerse en cuenta que: a) los números del conjunto N pueden utilizarse en la secuencia de operaciones 0 o 1 vez, b) los resultados parciales de las operaciones pueden utilizarse como candidatos en operaciones siguientes, c) las operaciones que den como resultado valores negativos o números no enteros NO deberán tenerse en cuenta como secuencia válida para obtener una solución. Diseñe un algoritmo que obtenga una solución al problema propuesto, mostrando la secuencia de operaciones para obtener el número objetivo P. En caso de no existir solución alguna, el algoritmo deberá mostrar la secuencia de operaciones que dé como resultado el valor más próximo, por debajo, del número objetivo P. Por ejemplo, siendo P=960 y N=1,2,3,4,5,6, la secuencia de operaciones que obtiene la solución exacta es: ((((6*5)*4)*2)*(3+1))=960. Si P=970, el algoritmo no encontraría la solución exacta con el conjunto de números inicial y la secuencia más próxima por debajo de P sería ((((6*5)*4)*2)*(3+1))=960. Solución: Elección Razonada del Esquema Algorítmico.

Obviamente no se trata de un problema que pueda ser resuelto por divide y vencerás, puesto que no es posible descomponer el problema en subproblemas iguales, pero de menor tamaño, que con algún tipo de combinación nos permita encontrar la solución del problema.

Tampoco se trata de un algoritmo voraz, puesto que no existe ninguna manera de atacar el problema de manera directa que nos lleve a la solución sin necesidad de, en algún momento, deshacer alguna de las decisiones tomadas.

Por tanto, se trata de un problema de exploración de grafos donde deberemos construir el grafo implícito al conjunto de operaciones posibles con el fin de encontrar una solución al problema. Descartamos una exploración ciega en profundidad o en anchura puesto que, como en la mayor parte de los casos va a existir por lo menos una solución y además el enunciado del problema solicita una solución al problema y no todas, es deseable que la exploración se detenga en el momento en el que encuentre alguna de ellas. Sólo en el caso de que no exista solución al problema, a partir del conjunto N inicial, el recorrido deberá ser completo. De acuerdo a este razonamiento, la estrategia más apropiada parece la de aplicar un esquema del tipo backtracking o vuelta atrás. Como el alumno ya conoce, este tipo de algoritmos se basan en un recorrido en profundidad o en anchura que no construye el grafo implícito de manera exhaustiva, puesto que dispone de condiciones de corte que lo detienen en cuanto se encuentra una solución. En nuestro caso, además, basaremos el algoritmo en un recorrido en profundidad y no en anchura puesto que en la mayor parte de las ocasiones es necesario combinar prácticamente la totalidad de los elementos de N para obtener la solución. La alternativa de aplicar un algoritmo de ramificación y poda no es válida en este caso pues este tipo de algoritmos se caracteriza por obtener la solución óptima a un problema concreto. En este caso no es necesario optimizar absolutamente nada, pues la solución es el número objetivo que nos solicitan y no van a existir, por tanto, soluciones mejores o peores. Sólo en el caso de que no exista solución, el problema nos pide la más aproximada por debajo, lo cual implica una exploración exhaustiva del grafo implícito y, por tanto, el conocimiento por parte del algoritmo de cual ha sido la operación más aproximada realizada hasta el momento.

Page 186: Examenes resueltos

Descripción del Esquema Algorítmico de Vuelta Atrás.

fun vuelta-atrás(e: ensayo) si valido(e) entonces dev e sino listaensayos . complecciones(e) mientras ← vacia(listaensayos) . ←resultado hacer hijo . primero(listaensayos) listaensayos . resto(listaensayos) si condicionesdepoda(hijo) entonces resultado . vuelta-atrás(hijo) fsi fmientras dev resultado fsi ffun

Estructuras de Datos Necesarias La estructura de datos principal para llevar a cabo nuestro algoritmo va a ser aquella encargada de almacenar la información relativa a cada uno de los ensayos generados: Tipo Tensayo= candidatos: vector de int operaciones: vector de TpilaOperaciones solucion: boolean vacio: boolean Operaciones Asociadas --------------------- getCandidatos():vector Devuelve el vector de candidatos para operar con él. getOperaciones():vector Devuelve el vector de operaciones(pilas) para operar con él. getCandidato(indexCand int):int Devuelve el candidato que se encuentra en la posición indexCand. removeCandidato(indexCand int):void Elimina el candidato que se encuentra en la posición indexCand. setCandidato(candidato int,indexCand int):void Inserta el candidato candidato en la posición indexCand del vector de candidatos. getOperacion(indexOp int):TPilaOperaciones Devuelve la operación(pila) que se encuentra en la posición indexOp. removeOperacion(indexOp int):void Elimina la pila de operaciones que se encuentra en indexOp. setOperacion(operacion TpilaOperaciones, indexOp int):void Inserta la pila de operaciones operación en la posición indexOp del vector de operaciones. setSolucion(solucion boolean):void Marca el ensayo como solución válida. isSolucion():boolean Devuelve un boolean que indica si el ensayo es o no solución. isVacio():bolean Devuelve un bolean que indica si el ensayo es o no vacio. setVacio(vacio boolean)void Marca el ensayo como vacio.

Page 187: Examenes resueltos

Tipo TpilaOperaciones= pila: pila de String Operaciones Asociadas --------------------- pushNumber(value int):void

Añade un número a la pila. La lógica de la operación transforma el entero de entrada en una cadena de caracteres para poder insertarlo en la pila.

pushOperator(oper char):void Añade un operador a la pila. La lógica de la operación transforma el entero de entrada en una cadena de caracteres para poder insertarlo en la pila.

El principal problema del ejercicio se encuentra en determinar cómo vamos a ir construyendo el grafo implícito y cómo vamos a representar las operaciones que ya han sido llevadas a cabo. Para ello vamos a tener en cuenta lo siguiente:

1. Nuestro algoritmo siempre va a trabajar sobre un conjunto de candidatos que recogerá inicialmente los valores asociados y, posteriormente, los valores obtenidos al ir realizando cada una de las operaciones. Esta es la función del elemento candidatos de Tensayo.

2. Para poder recordar qué operaciones se han llevado a cabo y mostrárselas al usuario al fin del algoritmo, es necesario desplegar un almacén de información paralelo a candidatos que, para cada uno de los candidatos recoja las operaciones que éste ha soportado hasta el momento. Con este fin se crea el elemento operaciones, que no es más que un vector donde cada elemento representa una pila de operaciones y operandos que, en notación postfija, representan el historial de operaciones de dicho elemento.

3. Finalmente, el elemento solución marca el ensayo como solución o no, dependiendo si alberga la solución al problema.

Veamos con un ejemplo el funcionamiento de esta estructura de datos. Supongamos que nuestro conjunto inicial es N=1, 2, 3, 4. El ensayo correspondiente a esta situación inicial vendría descrito por: Tipo Tensayo= candidatos: vector de int operaciones: vector de TpilaOperaciones solucion: bolean ENSAYO ------ candidatos:<1,2,3,4> operaciones < > solucion: false

Supongamos ahora que operamos el candidato 2 y el candidato 4 con el operador ‘+‘. El nuevo formato del ensayo sería el siguiente: ENSAYO ------ candidatos:<1,6,3> operaciones < > solucion: false vacio: false

Nótese que:

1. Desaparece el elemento que ocupa la posición 3 del vector y su pila asociada. 2. El vector de candidatos ahora almacena el valor 6 allí donde se ha realizado la operación. 3. El vector de operaciones ha actualizado la pila de operaciones, reflejando la nueva situación en notación

postfija (2,4,+)

1 2 4 3

1 +

4

3

2

Page 188: Examenes resueltos

Supongamos que ahora operamos el candidato 6 con el candidato 3 utilizando el operador ‘-‘. El nuevo ensayo quedaría: ENSAYO ------ candidatos:<1,3> operaciones < > solucion: false vacio: false

Finalmente si operamos el candidato 1 con el candidato 3 utilizando el operador ‘*’. El ensayo obtenido sería: ENSAYO ------ candidatos:<3> operaciones < > solucion: false vacio: false

Como podemos observar, el valor final obtenido combinando todos los valores iniciales, y de acuerdo a las operaciones descritas, sería 3 y el historial completo de todas las operaciones realizadas podría mostrarse deshaciendo la pila en formato postfijo generada (2,4,+,3,-,1,*).

1

+

4

-

2

3

1

+

4

-

2

3

*

Page 189: Examenes resueltos

Algoritmo Completo.

fun vuelta-atrás(e: Tensayo):Tensayo si valido(e) entonces solucion . e solucion.setSolucion(true); dev solucion sino listaensayos . complecciones(e) mientras ← vacia(listaensayos) . ←solucion.isSolucion() hacer hijo . primero(listaensayos) listaensayos . resto(listaensayos) si ←podar(hijo) entonces solucion . vuelta-atrás(hijo) sino solucion . mejor(e) fsi fmientras dev solucion fsi ffun

Nótese que solución es un ensayo, que inicialmente es vacío, y que contendrá la solución en caso de existir o la serie de operaciones que más se aproximen en caso de que esto no ocurra. Solución se define externamente a la función vuelta-atrás y, por eso, puede manipularse desde cualquiera de las funciones sin ser necesario enviarla a éstas como parámetro. Igualmente, la el valor objetivo P, también es utilizado globalmente por la función vuelta atrás. Las funciones asociadas al algoritmo son las siguientes: valido(e Tensayo):boolean

Función que devuelve true si el ensayo que recibe como parámetro es solución al problema, es decir, si contiene algún candidato cuyo valor sea P. Devuelve false en caso contrario.

complecciones(e Tensayo):lista Función que devuelve la lista de hijos correspondientes a un ensayo concreto. La política de generación de hijos que seguiremos será la siguiente: Para cada candidato, complecciones genera todas las combinaciones posibles de éste con cada uno de los demás, haciendo uso del conjunto de operaciones posibles.

podar(e Tensayo):bolean Función que devuelve un boolean dependiendo si es posible continuar explorando por el ensayo e que recibe como parámetro o no. La única condición de poda que impondremos será que alguno de los candidatos calculados hasta el momento sobrepase el valor de P.

mejor(e Tensayo):Tensayo Función que compara el ensayo e, que recibe como parámetro, con la solución calculada hasta el momento. Devuelve a la salida aquel ensayo que contenga el candidato más próximo a la solución solicitada.

fun valido(e: Tensayo):boolean

para c desde 0 hasta numCandidatos hacer candidato . e.getCandidato(c) si candidato = P entonces dev true fsi fpara dev false ffun

fun podar(e: Tensayo):boolean para c desde 0 hasta numCandidatos hacer candidato . e.getCandidato(c) si candidato > P entonces dev true fsi fpara dev false ffun

Page 190: Examenes resueltos

fun mejor(e: Tensayo):Tensayo v1 . valorMax(e) v2 . valorMax(solucion) si v1<v2 entonces dev solucion sino dev e fsi

ffun

fun valorMax(e: Tensayo):int value . e.getCandidato(0)

para cada c desde 1 hasta numCandidatos hacer valAux . e.getCandidato(c) si (valAux>value) . (valAux<=P) entonces value=valAux fsi fpara dev value ffun

fun complecciones(e: Tensayo):vector

para c1 desde 0 hasta numCandidatos hacer para c2 desde c1+1 hasta numCandidatos hacer hijo=obtieneHijo(e,’+’,c1,c2) si (←hijo.isVacio()) entonces vHijos.addElement(hijo) fsi hijo=obtieneHijo(e,’-’,c1,c2) si (←hijo.isVacio()) entonces vHijos.addElement(hijo) fsi hijo=obtieneHijo(e,’*’,c1,c2) si (←hijo.isVacio()) entonces vHijos.addElement(hijo) fsi hijo=obtieneHijo(e,’/’,c1,c2) si (←hijo.isVacio()) entonces vHijos.addElement(hijo) fsi fpara fpara dev vHijos ffun

Page 191: Examenes resueltos

fun obtieneHijo(e: Tensayo, char operator, int c1Index, int c2Index):Tensayo c1 . e.getCandidato(c1Index) c2 . e.getCandidato(c2Index) nuevoEnsayo . e si (operator=’+’) entonces res . c1+c2 sino si (operator=’-‘) entonces res . c1-c2 sino si (operator=’*’) entonces res . c1*c2 sino si (operator=’/’) entonces si (c2!=0) . (c1%c2=0) entonces res . c1/c2 sino res . -1 fsi fsi fsi fsi fsi si (res >=0) entonces nuevoEnsayo . e pila1=e.getOperacion(c1) pila2=e.getOperacion(c2) pila=generaNuevaPila(pila1,pila2,operator) nuevoEnsayo.removeCandidato(c2) nuevoEnsayo.setCandidato(res,c1) nuevoEnsayo.removeOperacion(c2) nuevoEnsayo.setOperacion(pila,c1) dev nuevoEnsayo sino dev ensayoVacio fsi

ffun

Nótese como la funcion generaNuevaPila recibe como parámetros las dos pilas ya existentes (pertenecientes a cada uno de los candidatos), así como el operador que va a ser utilizado para combinar ambos candidatos y genera como resultado la nueva pila correspondiente al candidato generado.

Page 192: Examenes resueltos
Page 193: Examenes resueltos
Page 194: Examenes resueltos
Page 195: Examenes resueltos

Prueba Presencial

Segunda Semana

Enero - Febrero de 2005

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Programación III

Solución

Duración: 2 horasMaterial permitido: NINGUNO

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico 2. Descripción del esquema usado e identificación con el problema 3. Estructuras de datos 4. Algoritmo completo a partir del refinamiento del esquema general 5. Estudio del coste

Cuestión 1 (2 puntos). Demuestra cuál es el orden exacto de complejidad en función de la variable n, del siguiente programa:

1 procedimiento lona (n: entero, j: entero) 2 para i desde 1 hasta n div 4 hacer 3 j:=j+i; 4 fpara 5 si n>1 entonces 6 lona(n-2,j); 7 escribir “j”; 8 lona(n-2,n-j); 9 fsi

Planteamos una recurrencia con reducción del problema mediante sustracción

n: tamaño del problemas a: número de llamadas recursivas b: reducción del problema en cada llamada recursiva n-b: tamaño del subproblema nk: coste de las instrucciones que no son llamadas recursivas

Recurrencia: c·nk si 0≤n<b T(n)= a·T(n-b)+c·nk si n≥b Θ(nk) si a<1 T(n)∈ Θ(nk+1) si a=1 Θ(an div b) si a>1 a=2; b=2; nk=n; k=1 Por tanto, T(n)∈ Θ(2n div 2) Nota: Θ(2n div 2) no es equivalente a Θ(2n), puesto que se le está aplicando la raíz cuadrada y no el producto de una constante.

Page 196: Examenes resueltos

Cuestión 2 (1 punto). ¿En qué se diferencia una búsqueda ciega en profundidad y un esquema de vuelta atrás? Pon un ejemplo. El esquema de vuelta atrás es una búsqueda en profundidad pero en la que se articula un mecanismo para detener la búsqueda en una determinada rama (poda). Para alcanzar una solución final es necesario que los pasos intermedios sean soluciones parciales al problema. Si un determinado nodo no es una solución parcial, entonces la solución final no se puede alcanzar a partir de dicho nodo y la rama se poda. Esto se implementa en el esquema de vuelta atrás mediante la función condiciones_de_poda o función de factibilidad. El problema de colocar N reinas en un tablero de NxN sin que se amenacen entre sí es un problema que se puede resolver mediante vuelta atrás, puesto que en cada nivel de la búsqueda se establece un problema parcial: en el nivel i se trata de colocar i reinas en un tablero de NxN sin que se amenacen entre sí. Si un nodo no cumple esta condición, por muchas más reinas que se coloquen a continuación nunca se va a encontrar una solución final. Cuestión 3 (2 puntos). Demuestra por inducción que el algoritmo de Dijkstra halla los caminos mínimos desde un único origen hasta todos los demás nodos del grafo. (Solución en el libro de texto, Brassard, pág. 225). Problema (5 puntos). Utiliza el esquema de divide y vencerás para implementar una función que tome un vector de enteros y le dé estructura de montículo con el menor coste posible. 1. Elección del esquema (0 puntos) No es necesario razonar la elección del esquema puesto que viene impuesto en el problema. 2. Esquema general (0.5 puntos)

1. Descomponer el ejemplar en subejemplares del mismo tipo que el ejemplar original 2. Resolver independientemente cada subejemplar (subproblema) 3. Combinar los resultados para construir la solución del ejemplar original

Función DivideVencerás(X) si suficiente_pequeño(X) entonces dev subalgoritmo_básico(X) si no Descomponer(X, X1..Xn) para i=1 hasta n hacer Yi:=DivideVencerás(Xi); fpara Recombinar(Y1..Yn, Y) dev Y fsi

Page 197: Examenes resueltos

3. Estructuras de datos (0 puntos)

No se necesita ninguna estructura adicional a parte del vector de entrada.

4. Algoritmo completo (3 puntos) Como se trata de un árbol binario, descomponemos el problema en los dos subárboles bajo el nodo i, es decir, el que tiene por raíz 2i y el que tiene por raiz 2i+1. Cada subárbol a su vez debe tener estructura de montículo lo que resulta un problema del mismo tipo que el original y, por tanto, corresponde a sendas llamadas recursivas, una para 2i y otra para 2i+1. Por último, hay que colocar la raíz i en su lugar. Para ello, hay que “hundirla”.

Procedimiento crear_montículo(i, M[1..m])

si 2i<m entonces

crear_montículo(2i, M)

fsi

si (2i+1)<m entonces

crear_montículo(2i+1, M)

M[7]M[8]

1

7

25

612

74

9

M[1]

M[2] M[3]

M[4] M[5] M[6]

M[9]M[10]

fsi

si (2i≤m) entonces

hundir(M, i)

fsi

La llamada inicial será: crear_montículo(1,M). Como puede observarse, dividir el vector en dos mitades M[1..m/2], M[(m/2)+1..m] y tratar de resolver cada una de ellas supone un error. Una solución que recorra completamente el vector y proceda a hundir o flotar cada elemento siempre tendrá mayor coste. Ya que estamos en un esquema divide y vencerás, podemos plantear el procedimiento hundir como un problema de reducción. Únicamente se tiene que decidir si el nodo debe intercambiarse por alguno de sus hijos, y en caso afirmativo intercambiarse con el mayor de ellos y realizar la correspondiente llamada recursiva para seguir “hundiéndose”.

Procedimiento hundir(T[1..n], i)

hmayor:=i

si (2i ≤ n) y (T[2i] > T[hmayor]) entonces

hmayor=2i

Page 198: Examenes resueltos

fsi

si (2i < n) y (T[2i+1] > T[hmayor]) entonces

hmayor=2i+1

fsi

si (hmayor > i) entonces

intercambiar(T[i], T[hmayor])

hundir(T[1..n], hmayor)

fsi 5. Estudio del coste (1.5 puntos) El coste del procedimiento hundir se puede plantear mediante una recurrencia con reducción del problema por división, ya que hundir prosigue por uno de los dos subárboles y, por tanto, el problema se ha reducido a la mitad. c·nk si 0≤n<b T(n)= a·T(n/b)+c·nk si n≥b Θ(nk) si a<bk

T(n)∈ Θ(nk log n) si a=bk

Θ(nlogb

a) si a>bk

a=1; b=2; c·nk=c, k=0; a=bk luego T(n)∈Θ(log n) El coste de crear_montículo puede expresarse, entonces mediante la siguiente recurrencia: T(n)=2·T(n/2)+log n Sin embargo, esta recurrencia no se puede resolver con la fórmula anterior puesto que la parte no recursiva no tiene una complejidad polinomial. Para resolverlo, vamos a utilizar un cambio de variable: Sea h la altura del montículo de n nodos: h=log2 n. En cada llamada recursiva bajamos un nivel por lo que el problema se puede expresar mediante una recurrencia con reducción del problema por sustracción. Es decir, si en cada paso se baja un nivel, el problema se reduce en uno. c·nk si 0≤n<b T(n)= a·T(n-b)+c·nk si n≥b Θ(nk) si a<1 T(n)∈ Θ(nk+1) si a=1 Θ(an div b) si a>1

Page 199: Examenes resueltos

En el caso de hundir T(h)=T(h-1)+c, con a=1 y b=1, luego T(h)∈Θ(h), que deshaciendo el cambio de variable lleva a un tiempo en función de n: T(n)∈Θ(log n) como habíamos demostrado antes. Sin embargo, ahora ya podemos plantear la recurrencia para crear_montículo: T(h)=2·T(h-1)+h, donde a=2 y b=1 y, por tanto, T(h)∈Θ(2h). Deshaciendo el cambio de variable: 2h=2log

2 n=n, y T(n)∈Θ(n), que es el menor coste posible para dar estructura de montículo a un

vector. NOTA: cualquier solución que tenga mayor coste no será puntuada.

Page 200: Examenes resueltos
Page 201: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2005 – Original Cuestión 1 (2 puntos). Suponga que N personas numeradas de 1 a N deben elegir por votación a una entre ellas. Sea V un vector en el que la componente V[i] contiene el número del candidato que ha elegido el votante i. ¿Qué algoritmo utilizarías para determinar con un coste lineal si una persona ha obtenido más de la mitad de los votos? Cuestión 2 (1 punto). En el contexto de elegir un esquema algorítmico para resolver un problema de optimización con restricciones, ¿cuándo se puede resolver mediante un esquema voraz y en qué casos sería necesario utilizar un esquema de ramificación y poda? Cuestión 3 (2 puntos). Sea T(n)=4n2-3n+2 el tiempo de ejecución de un algoritmo. Demuestra si es cierta o falsa cada una de las siguientes afirmaciones (0.5 puntos cada una):

2

3

2

( ) ( log )( ) ( )( ) ( log )( ) ( )

T n O n nT n O nT n n nT n O n

∉∈Ω

PROBLEMA (5 puntos). Sea V[1..N] un vector con la votación de unas elecciones. La componente V[i] contiene el nombre del candidato que ha elegido el votante i. Implementa un programa cuya función principal siga el esquema divide y vencerás, que decida si algún candidato aparece en más de la mitad de las componentes (tiene mayoría absoluta) y que devuelva su nombre. Sirva como ayuda que para que un candidato tenga mayoría absoluta considerando todo el vector (al menos N/2+1 de los N votos), es condición necesaria pero no suficiente que tenga mayoría absoluta en alguna de las mitades del vector. La resolución del problema debe incluir, por este orden: 1. Descripción del esquema divide y vencerás y su aplicación al problema (0.5 puntos). 2. Algoritmo completo a partir del refinamiento del esquema general (3 puntos) 3. Estudio del coste del algoritmo desarrollado (1.5 puntos)

Page 202: Examenes resueltos
Page 203: Examenes resueltos

Programación III

Solución

Prueba Presencial

Original

Septiembre de 2005

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Prueba Presencial

Duración: 2 horasMaterial permitido: NINGUNO

Cuestión 1 (2 puntos). Suponga que N personas numeradas de 1 a N deben elegir por votación a una entre ellas. Sea V un vector en el que la componente V[i] contiene el número del candidato que ha elegido el votante i. ¿Qué algoritmo utilizarías para determinar con un coste lineal si una persona ha obtenido más de la mitad de los votos? Podría utilizarse una estrategia similar a la que emplea para ordenación el algoritmo de la casilla (página 80 del libro), pero trasladado al conteo de elementos. La siguiente función almacena en el vector votos el número de votos que va sumando cada candidato votado. Devuelve un valor TRUE si hay alguno con mayoría indicando de qué candidato se trata:

función contar_votos(V[1..N) dev (booleano, elegido) votos[1..N]=0; para i=1 hasta N hacer

votos[V[i]]=votos[V[i]]+1; si votos[V[i]]>N/2 entonces devolver (TRUE,V[i]) fsi; fpara devolver (FALSE,0);

Cuestión 2 (1 punto). En el contexto de elegir un esquema algorítmico para resolver un problema de optimización con restricciones, ¿cuándo se puede resolver mediante un esquema voraz y en qué casos sería necesario utilizar un esquema de ramificación y poda? Para resolverlo con un esquema voraz es necesario que exista una función de selección de candidatos y una función de factibilidad que decida si se acepta o rechaza el candidato, de manera que la decisión es irreversible. Si no es posible encontrar las funciones de selección y de factibilidad de manera que se garantice que la elección de un candidato lleva a la solución óptima, entonces optaríamos por otro esquema como el de ramificación y poda. Cuestión 3 (2 puntos). Sea T(n)=4n2-3n+2 el tiempo de ejecución de un algoritmo. Demuestra si es cierta o falsa cada una de las siguientes afirmaciones (0.5 puntos cada una):

Recordamos la regla del límite:

))(()()),(()())(()()),(()(0

))(()(

)()(lím

nngnfngnfentoncesngnfngOnfentonces

ngnfentoncesc

ngnf

Θ∉Ω∈∞+Θ∉∈

Θ∈

⎪⎩

⎪⎨

⎧=

∞→

a) T(n) ∉ O(n2 ln n)

Luego pertenece al orden indicado y la cuestión a) es FALSA

03ln2

8ln2

38límln

234límn2

2

n=

+=

+−

=+−

∞→∞→ nnnnn

nnnn

b) T(n) ∉ O(n3)

068

338lím234lím 2n3

2

n==

−=

+−∞→∞→ nn

nn

nn

Page 204: Examenes resueltos

Por lo que T(n) pertenece a O(n3 ) y la cuestión b) es FALSA c) T(n) ∈ Ω(n log n)

con lo que c) es CIERTO

+∞==+−

=+−

∞→∞→

nn

nnnnn

18

1ln38lím

ln234lím

n

2

n

d) T(n) ∈ O(n2)

En este caso, al ser T(n) ∈ Θ(n2) se cumple también que T(n) ∈ O (n2) luego d) es CIERTO

+

∞→∞→ℜ∈==

−=

+− 428

238lím234lím

n2

2

n nn

nnn

Problema (5 puntos). Sea V[1..N] un vector con la votación de unas elecciones. La componente V[i] contiene el nombre del candidato que ha elegido el votante i. Implementa un programa cuya función principal siga el esquema divide y vencerás, que decida si algún candidato aparece en más de la mitad de las componentes (tiene mayoría absoluta) y que devuelva su nombre. Sirva como ayuda que para que un candidato tenga mayoría absoluta considerando todo el vector (al menos N/2+1 de los N votos), es condición necesaria pero no suficiente que tenga mayoría absoluta en alguna de las mitades del vector. La resolución del problema debe incluir, por este orden:

1. Descripción del esquema divide y vencerás y su aplicación al problema (0.5 puntos).

El esquema general Divide y Vencerás consiste en: 1. Descomponer el ejemplar en subejemplares del mismo tipo que el original 2. Resolver independientemente cada subejemplar 3. Combinar los resultados para construir la solución del ejemplar original

Más formalmente: Función DivideVencerás(X) dev Y si suficiente_pequeño(X) entonces dev subalgoritmo_básico(X) si no (X1..Xn)=Descomponer(X); para i=1 hasta n hacer Yi:=DivideVencerás(Xi); fpara Y=Recombinar(Y1..Yn); dev Y; fsi

Page 205: Examenes resueltos

2. Algoritmo completo a partir del refinamiento del esquema general (3 puntos)

función contar(V[1..N], i, j) dev (tiene_mayoría, candidato, num_votos) si (i==j) entonces

dev (TRUE, V[i], 1) si no

/* Descomponer */ (tiene_mayoría1, candidato1, num_votos1)=contar(V, i, (i+j)÷2); (tiene_mayoría2, candidato2, num_votos2)=contar(V, (i+j)÷2+1, j); /* Recombinar */ si tiene_mayoría1 entonces

para k desde (i+j)÷2+1 hasta j hacer si es_igual(V[k], candidato1) entonces

num_votos1=num_votos1+1; fsi

fpara si (num_votos1>(j-i+1)/2) entonces

devolver (cierto, candidato1, num_votos1); fsi

fsi si tiene_mayoría2 entonces

para k desde i hasta (i+j)÷2 hacer si es_igual(V[k], candidato2) entonces

num_votos2=num_votos2+1; fsi

fpara si (num_votos2>(j-i+1)/2) entonces

devolver (cierto, candidato2, num_votos2); fsi

fsi devolver (falso,””,0);

fsi Llamada inicial contar(V,1,N); 3. Estudio del coste del algoritmo desarrollado (1.5 puntos)

Planteamos la ecuación de recurrencia T(n) = 2·T(n÷2) + n÷2 + n÷2 = 2·T(n÷2) + n La reducción del problema se realiza mediante división, cuyos casos son los siguientes:

Θ(nk) si a<bk T(n) = Θ(nk log n) si a=bk Θ(nlogba) si a>bk

donde: n: tamaño del problema a: número de llamadas recursivas n/b: tamaño del subproblema nk: coste de las instrucciones que no son llamadas recursivas

Aplicado a nuestro problema:

c·nk=n; k=1; b=2; a=2; bk=21=2

a=bk luego T(n) ∈ Θ(n log n)

Page 206: Examenes resueltos
Page 207: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2005– Reserva Cuestión 1 (1 punto). Dado [ ]2,6, 4,12,7, 4, 4m = . Comprobar si es o no montículo de mínimos. Si no lo es, programar una función para convertirlo en montículo y aplicarla a ‘m’. Sino, programar una función de añadir elemento mediante la función “flotar” y aplicarlo al valor 3. En ambos casos escribir el montículo resultante y detallar todos los pasos. Cuestión 2 (2 puntos). Demostrar formalmente si existe relación de pertenencia entre f(n) y ( )( )O g n

Y también entre g(n) y ( )( )O f n considerando ( ) 2nf n = y ( ) 22 ng n = . Cuestión 3 (2 puntos). Analizar y hallar el coste de los algoritmos siguientes (Considerar de orden ( )2nΟ la función ( ), ,h n r i )

Problema (5 puntos). El Sudoku es un pasatiempo consistente en rellenar con cifras del 1 al 9 una cuadrícula de 81 (9x9) casillas distribuidas a su vez en 9 cajas de 3x3. El juego consiste en rellenar cada caja de 9 casillas con cifras del 1 al 9 sin repetirlas. No se pueden repetir tampoco cifras en líneas o columnas de la cuadrícula. Se pide diseñar un algoritmo que complete por nosotros este pasatiempo. La tabla adjunta muestra un ejemplo resuelto.

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. (0,25) 2. Refinamiento e identificación con el problema. (0,5) 3. Estructuras de datos. (0,25) 4. Algoritmo completo a partir del refinamiento del esquema general. (3,5) 5. Estudio del coste. (0,5)

PROCEDIMIENTO a (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 3 ENTONCES DEVOLVER(1); SINO COMIENZO r ← a (n DIV 2, k-1); r ← r + a (n DIV 2, k+1); PARA i ← 1 HASTA n^2 HACER r ← r + k; DEVOLVER (r); FIN FIN

PROCEDIMIENTO b (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 4 ENTONCES DEVOLVER(1); SINO COMIENZO r ← r + b (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + b (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 208: Examenes resueltos
Page 209: Examenes resueltos

Proc añadir - nodo (T[1...n],v)T[n+1] vFlotar(T[1...n+1],n+1)

Fproc

Proc Flotar(V[1...n],i)k iRepetirj k

Si j > 1 y V[j 2] < V[k] entonces k j 2

Intercambiar V[j] y [k]Hasta j = k

Fproc

←÷

← ÷

Proc Intercambiar(int j,k); var aux; aux := V[j]; V[j] :=V[k]; V[k] := aux;Fproc Intercambiar;

RESPUESTAS EXAMEN Programación III. Septiembre 2005 (Reserva) Cuestión 1 (1 punto). Dado [ ]2,6, 4,12,7, 4, 4m = . Comprobar si es o no montículo de mínimos. Si no lo es, programar una función para convertirlo en montículo y aplicarla a ‘m’. Sino, programar una función de añadir elemento mediante la función “flotar” y aplicarlo al valor 3. En ambos casos escribir el montículo resultante y detallar todos los pasos. Como es un montículo de mínimos inserto el valor 3 al montículo [ ]2,6, 4,12,7, 4, 4m = , quedando de la

siguiente manera [ ]2,6, 4,12,7, 4, 4,3m = . Para que el vector siga manteniendo la estructura de montículo utilizo el procedimiento flotar, comparo [ ] [ ]4 8T T> como es mayor entonces k=4 y hago intercambio de j y k. [ ]2,6, 4,3,7, 4, 4,12m =

Con la variable actualizada k=4 vuelvo a comparar [ ] [ ]2 4T T> como es mayor entonces k=2 y hago

intercambio de j y k. [ ]2,3, 4,6,7, 4, 4,12m =

Con la variable actualizada k=2 vuelvo a comparar [ ] [ ]1 2T T> , en este caso no es mayor y por lo tanto

la variable j=k terminando el procedimiento. El montículo queda así: [ ]2,3, 4,6,7, 4, 4,12m =

2

6 4

12 7 4 4

Page 210: Examenes resueltos

Cuestión 2 (2 puntos). Demostrar formalmente si existe relación de pertenencia entre f(n) y ( )( )O g n

Y también entre g(n) y ( )( )O f n considerando ( ) 2nf n = y ( ) 22 ng n = . Primer compruebo que f(n) está en ( )( )O g n

( )( ) 2

2 2 1 1lim lim lim lim lim 02 2 2 2 2

n n

n n n nn n n n n

f ng n ∞→∞ →∞ →∞ →∞ →∞

= = = = =⋅

Y por la regla de los límites deducimos que ( ) ( )( )f n O g n∈ pero ( ) ( )( )g n O f n∉ En la segunda cuestión compruebo que g(n) está en ( )( )O f n

( )( )

22 2 2 2 2lim lim lim lim lim2 2 1 1

n n n n

n nn n n n n

g nf n

→∞ →∞ →∞ →∞ →∞

⋅= = = = = ∞

Y por la regla de los límites deducimos que ( ) ( )( )g n O f n∉ pero ( ) ( )( )f n O g n∈ Regla del límite:

1. Si ( )( )n

f nlim

g n+

→∞∈ℜ , entonces ( ) ( )( )f n O g n∈ y ( ) ( )( )g n O f n∈

2. Si ( )( )

0n

f nlim

g n→∞∈ , entonces ( ) ( )( )f n O g n∈ pero ( ) ( )( )g n O f n∉

3. Si ( )( )n

f nlim

g n→∞∈+∞ , entonces ( ) ( )( )f n O g n∉ pero ( ) ( )( )g n O f n∈

Page 211: Examenes resueltos

Cuestión 3 (2 puntos). Analizar y hallar el coste de los algoritmos siguientes (Considerar de orden ( )2nΟ la función ( ), ,h n r i )

El procedimiento uno tiene una instrucción condicional de coste constante. Dentro de la condición tiene: o bien una instrucción constante, que no tenemos en cuenta para el cálculo, o bien dos llamadas recursivas, ambas invocan la función con un tamaño n/2. //En el segundo caso de la llamada recursiva hay otra instrucción simple añadida. Un bucle en el que se repite n2 veces un cálculo consistente en una instrucción constante La expresión queda T(n) = T(n/2) + T(n/2) + n2 (1) lo que equivale a: T(n) = 2T(n/2) + n2. Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b)+cnk lo que equivale a T(n) = 2T(n/2) + n2 y siendo 2 < 2 2 el coste es O(n2). a = 2, b = 2, k = 2 el segundo algoritmo: está formado por una instrucción condicional de coste constante cuyo cuerpo incluye secuencialmente: (i) una llamada recursiva de tamaño n/2, (ii) un bucle en el que se repite n veces un cálculo consistente en llamar dos veces a una función h(n; r; i) de coste cuadrático, /*más una instrucción simple*/, y por último (v) una instrucción simple, que no tenemos en cuenta para el cálculo, y otra llamada recursiva de tamaño n/2. Sumando los términos nos sale T(n) = T(n/2)+ n (2n2)+T(n/2), lo que equivale a T(n) = 2T(n/2) + 2n3 , Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk y siendo 2 < 2 3 el coste es O(n3). a = 2, b = 2, k = 3

PROCEDIMIENTO a (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 3 ENTONCES DEVOLVER(1); SINO COMIENZO r ← a (n DIV 2, k-1); r ← r + a (n DIV 2, k+1); PARA i ← 1 HASTA n^2 HACER r ← r + k; DEVOLVER (r); FIN FIN

PROCEDIMIENTO b (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 4 ENTONCES DEVOLVER(1); SINO COMIENZO r ← r + b (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + b (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 212: Examenes resueltos

Problema (5 puntos). El Sudoku es un pasatiempo consistente en rellenar con cifras del 1 al 9 una cuadrícula de 81 (9x9) casillas distribuidas a su vez en 9 cajas de 3x3. El juego consiste en rellenar cada caja de 9 casillas con cifras del 1 al 9 sin repetirlas. No se pueden repetir tampoco cifras en líneas o columnas de la cuadrícula. Se pide diseñar un algoritmo que complete por nosotros este pasatiempo. La tabla adjunta muestra un ejemplo resuelto.

Solución: Es un problema de búsqueda no de optimización por lo tanto descarto el esquema voraz y el de ramificación y poda, tampoco se puede ir dividiendo el problema en subproblemas más pequeños, viendo esto me decanto por el esquema de vuelta atrás. Esquema general:

fun vuelta - atras(ensayo)si valido (ensayo) es una solucion entonces dev (ensayo)si no para cada hijo compleciones (ensayo)

si condiciones de poda (hijo) hacer v∈

uelta - atras(hijo) fsifpara

fsiffun

En nuestro caso, tendremos que un ensayo es una matriz de 9x9 donde probaremos los distintos candidatos hasta llegar a la solución (o no) tras recorrer todas las celdas de la matriz. Tomaremos el nodo-raíz como el nodo padre principal del que partiremos, o lo que denominaremos 0-prometedor. Los hijos serán los tableros con una posible solución valida siguiendo las reglas de Sudoku, que formarán las condiciones de poda en nuestro juego. Usaremos, siguiendo las condiciones que nos dicen en el enunciado los siguientes elementos: - Array de 10 booleanos para indicar los elementos ocupados en cada grupo de celdas. - Matriz de 9x9 de enteros, que será la matriz donde pondremos los distintos valores. - Array de 10 elementos de booleanos, que significa los posibles valores que tomaremos. - Array de 9 elementos de grupo de celdas, indicando elemento ocupado en fila, columna o cuadrante (o bloque). El ensayo (juego) del Sudoku lo formará lo siguiente: ocupado = array [0..9] de boolean; GrupoCeldas = array [0..9] de boolean; Tensayo = tupla arrayTab : vector [0..8][0..8] de integer; fil, col, blo: array[0..8] de GrupoCeldas; ftupla

Page 213: Examenes resueltos

Con la estructura de datos que hemos expuesto podremos expresar la función de vuelta-atrás, que en nuestro caso la hemos llamado resuelve. Nuestro ensayo será la matriz arrayCeldas. Tendremos el pseudocódigo que nos resolvería nuestro problema, que en nuestro caso lo hemos denominado resolver, correspondería a la función vuelta-atrás que es la siguiente: fun resolver (arrayCeldas:Tensayo) si (conCeldas = num*num) /* Llegamos a solución final */ esSolucion true; else calcula_posicion_actual (); /* Calcula posición en tablero de fila, columna y cuadrante */ /* Existe un número valido en el tablero ya introducido */ valor arrayCeldas[posición_en_fila][posición_en_columna]; si (valor != 0) marca_en_posicion (valor); contCeldas ++; /* Pasa a siguiente celda */ resuelve (arrayCeldas); /* Función recursiva, (k+1) prometedor */ si (¬ esSolucion) contCeldas --; /* Pasa a celda anterior */ fsi else /* Valor a resolver, significa 0 en el tablero */ i 1 contCeldas ++; /* Pasa a siguiente celda */ mientras ((¬ esSolucion) ^ (i <= num)) /* Elemento no se está usando en el tablero */ si (¬ estaUtilizando_posicion (i)) Guarda_candidato(arrayCeldas, i); marca_en_posicion (i); /* Cuando tomamos un candidato y no es solución, desmarcamos en fila, columna y cuadrante para dejar los candidatos ya usados libres */ si (!esSolucion) desmarca_en_posicion (); fsi fsi i ++; fmientras si (¬ esSolucion) /* Se ha recorrido los 9 valores en una celda y no es solución */ contCeldas --; poner_a_cero_celda(); fsi fsi fsi ffun Veremos el pseudocódigo para analizar si el tablero es valido, que denominaremos con esValido. Está función devolverá true (1) si el tablero cumple las reglas del Sudoku y 0 en caso contrario. Tendríamos lo siguiente: fun esValido(): booleano para i 0 a 8 hacer para j 0 a 8 hacer si (arrayTab[i][j] > 0) calcula_posicion_actual(); valorActual arrayTab[fila_actual][columna_actual]; si (¬ estaUtilizando_posicion()) devolver false else marca_en_posicion (valorActual); fsi fsi fpara fpara devolver true; ffun En el pseudocódigo las funciones auxiliares serán iguales que vimos anteriormente. En nuestro caso calculará la posición actual y comprobaremos que en el valor actual se verifique dichas reglas.

Page 214: Examenes resueltos

Por último, en la función principal tendremos que primero se tendrá que comprobar el tablero para ver si cumple dichas reglas y luego resolverlo, es por tanto, que se tendrá que hacer lo siguiente: si (esValido()) resolver(arrayTab); fsi Como hemos visto en nuestra estructura de datos, la matriz arrayTab guardará el tablero que inicialmente se nos da para resolver. Los valores a resolver, que son los * se guardarán en el mismo como 0. Como hemos visto en la función en pseudocódigo anterior, si el valor es mayor de 0 significa que en los datos que se nos da está rellenado, o lo que equivale a un valor que no hace falta analizar, sólo hace falta quitarlo de la lista de elementos o como antes expresamos marcar como ocupado. Conceptualmente es similar. 3. Analiza el coste en términos de computabilidad computacional. Analizaremos para el caso peor, en el que habrá que recorrer todas las casillas sin llegar a ninguna solución. O lo que es lo mismo en nuestro algoritmo, cuando no se llega a solución (esSolucion a false). Es difícil hacer un análisis completo en términos de la computabilidad computacional, ya que al ser recursivo es difícil saber el coste de la recursión, es decir, de la función recursiva de la que parte. No podremos, por tanto, averiguar el coste exacto de la misma. Lo único que tenemos constancia es del número de celdas a recorrer y de los valores (o candidatos) que recorreremos en cada celda. Es, por tanto, que la cota superior del coste es nnúmero de celdas , siendo:

n: valores a comprobar en celda. número de celdas: El total que antes hemos expresado, como 9*9 = 81.

Una primera aproximación seria coste T(n) ∈О(nnúmero de celdas), equivaliendo, por tanto, a T(n) ∈ О(981). Una segunda aproximación y quizás la mas cercana a la realidad de nuestro algoritmo recursivo es suponer todos los posibles nodos-hijos (o hijo-nodo) como un árbol, en la que tomaremos todos los valores. El esquema sería como sigue: Nodo padre ……. 9 hijos 9*9 hijos … Podremos seguir representando el árbol, hasta recorrer los posibles valores. Vemos que el primer número pertenece al número de hijo, el segundo al valor que trataremos en el primer nivel de hijos. En el segundo, el primer número será el de hijo, el segundo el del valor del padre (en este caso es el nodo 1) y el tercer número el de los distintos valores. Observamos que del nodo hijo con valor dos en el primer nivel no tiene ningún hijo, esto se hizo así por problemas con el dibujo realizado. Supondremos por tanto, que tiene tantos hijos como el resto de nodos hermanos. Observamos por tanto, que aquí tendremos como cota superior T(n) ∈О(n!), al ser una progresión aritmética. Empezaremos por 0 (90) hijos, seguiremos por 9 (91) hijos, para seguir por 81 (92) hijos, así continuamente nos dará el factorial de n!

0

1;1 1;2 1;9

2;1;1 2;1;2 2;1;9 2;9;1 2;9;2 2;9;9

Page 215: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2006 – Primera semana Cuestión 1 (2,5 puntos). ¿En qué se diferencia una búsqueda ciega en profundidad y un esquema de vuelta atrás? (0.5 puntos) Cuestión 2 (1,5 puntos). Declara en Java o en Módula-2 las clases y/o estructuras de datos que utilizarías en el problema del Sudoku (práctica de este año) para comprobar en un tiempo de ejecución constante respecto a la dimensión n del tablero (nxn) que una casilla contiene un valor factible. Cuestión 3 (2 puntos). Dado el siguiente grafo, rellena la tabla adjunta indicando paso a paso cómo el algoritmo de Dijkstra encuentra todos los caminos de menor coste desde el nodo 1.

Distancias desde 1 Nodo Precedente PASO Nodo Seleccionado Nodo No Seleccionado 2 3 4 5 2 3 4 5

Problema (4 puntos). Una empresa de montajes tiene n montadores con distintos rendimientos según el tipo de trabajo. Se trata de asignar los próximos n encargos, uno a cada montador, minimizando el coste total de todos los montajes. Para ello se conoce de antemano la tabla de costes C[1..n,1..n] en la que el valor cij corresponde al coste de que el montador i realice el montaje j. Se pide: La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. (0,5) 2. Escribir el esquema general. (0,5) 3. Estructuras de datos. (0,5) 4. Algoritmo completo a partir del refinamiento del esquema general. (2,5)

Page 216: Examenes resueltos
Page 217: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2006 (Primera Semana) Cuestión 1 (2,5 puntos). ¿En qué se diferencia una búsqueda ciega en profundidad y un esquema de vuelta atrás? (0.5 puntos) La búsqueda ciega explora todas las ramas alternativas mientras que en un esquema de vuelta atrás se establecen condiciones de poda que determinan si una rama puede alcanzar o no una solución final. Si se determina que no es posible, entonces no se prosigue la búsqueda por dicha rama (se poda). Los problemas aptos para un esquema de vuelta atrás permiten expresar los nodos intermedios como soluciones parciales al problema. Aquellos nodos que no sean soluciones parciales no permiten alcanzar una solución final y, por tanto, su rama se poda. Por ejemplo, el problema de “poner N reinas en un tablero de NxN sin que se amenacen entre sí”, requiere ir solucionando la siguiente secuencia de soluciones parciales: poner 1 reina en un tablero de NxN sin que esté amenazada (trivial) poner 2 reinas en un tablero de NxN sin que se amenacen entre sí ... poner k reinas en un tablero de NxN sin que se amenacen entre sí ... poner N reinas en un tablero de NxN sin que se amenacen entre sí (solución final) Si por una rama no se puede resolver el problema para k, entonces evidentemente no se podrá resolver para N, por muchos intentos de añadir reinas hagamos. En el espacio de búsqueda, ¿qué significa que un nodo sea k-prometedor? (1 punto) Significa que es solución parcial para las k primeras componentes de la solución y, por tanto, todavía es posible encontrar una solución final (incluyendo las N componentes). En el problema de las N reinas habríamos colocado k reinas sin que se coman entre sí. ¿Que hay que hacer para decidir si un vector es k-prometedor sabiendo que es una extensión de un vector (k-1)-prometedor? (1 punto) Si es (k-1)-prometedor quiere decir que es solución parcial para las primeras k-1 componentes y que, por tanto, estas cumplen las restricciones necesarias entre sí y no hay que volver a verificarlas. Entonces, para decidir si una extensión considerando la siguiente componente k conforma un nodo k-prometedor, lo único que hay que hacer es verificar si esta nueva componente k cumple las restricciones respecto a las otras k-1.

Page 218: Examenes resueltos

Cuestión 2 (1,5 puntos). Declara en Java o en Módula-2 las clases y/o estructuras de datos que utilizarías en el problema del Sudoku (práctica de este año) para comprobar en un tiempo de ejecución constante respecto a la dimensión n del tablero (nxn) que una casilla contiene un valor factible. Existen varias alternativas, pero de nada sirve que verificar una casilla se realice en tiempo constante si luego actualizar su valor se realiza en tiempo lineal. En la siguiente solución se declaran tres tablas de booleanos que indican si ya hay o no un determinado valor en una determinada fila, columna o región, respectivamente. Si no es así, entonces es factible poner el valor en la casilla. Tanto la función de verificación como las de actualización tienen un coste computacional constante. public class Tablero

int N=9; int subN=(int)Math.sqrt(N); boolean val_en_fil[][] = new boolean[N][N]; boolean val_en_col[][] = new boolean[N][N]; boolean val_en_reg[][] = new boolean[N][N]; boolean valorFactible(int fil, int col, int val)

int g=region(fil,col); re return (!val_en_fil[fil][val] &&

!val_en_col[col][val] && !val_en_reg[reg][val]);

void poner(int fil, int col, int val)

int reg=region(fil,col); val_en_fil[fil][val]=true; val_en_col[col][val]=true; val_en_reg[reg][val]=true;

void quitar(int fil, int col, int val)

int reg=region(fil,col); val_en_fil[fil][val]=false; val_en_col[col][val]=false; val_en_reg[reg][val]=false;

int region(int fil, int col)

return (col/subN)*subN+fil/subN; // división entera

Cuestión 3 (2 puntos). Dado el siguiente grafo, rellena la tabla adjunta indicando paso a paso cómo el algoritmo de Dijkstra encuentra todos los caminos de menor coste desde el nodo 1.

Distancias desde 1 Nodo Precedente PASO Nodo Seleccionado Nodo No Seleccionado 2 3 4 5 2 3 4 5

0 1 2,3,4,5 3 ∞ 5 ∞ 1 1 1 1 1 1,2 3,4,5 3 9 4 14 1 2 2 2 2 1,2,4 3,5 3 6 4 14 1 4 2 2 3 1,2,3,4 5 3 6 4 7 1 4 2 3

Page 219: Examenes resueltos

Problema (4 puntos). Una empresa de montajes tiene n montadores con distintos rendimientos según el tipo de trabajo. Se trata de asignar los próximos n encargos, uno a cada montador, minimizando el coste total de todos los montajes. Para ello se conoce de antemano la tabla de costes C[1..n,1..n] en la que el valor cij corresponde al coste de que el montador i realice el montaje j. Se pide: 1. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Razonar la respuesta. (0.5 puntos) Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. (0,5 puntos) Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias. (0,5 puntos) nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; filas_no_asignadas: lista de cardinal; coste: cardinal; Montículo de mínimos (cota mejor la de menor coste) Desarrollar el algoritmo completo. (2,5 puntos) Las funciones generales del esquema general que hay que instanciar son: 1. a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) 2. b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” 3. c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores posibles para asignaciones[último_asignado+1]) 4.

Page 220: Examenes resueltos

Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0; nodo.coste=0; cota:=acotar(nodo,costes); poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras

devolver ∅; Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer minimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota; Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista; Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 221: Examenes resueltos

4. Desarrollar el algoritmo completo (2.5 puntos)

Las funciones generales del esquema general que hay que instanciar son:

a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores

posibles para asignaciones[último_asignado+1])

Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0;

nodo.coste=0; cota:=acotar(nodo,costes);

poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras devolver ∅;

Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer mínimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota;

Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista;

Page 222: Examenes resueltos
Page 223: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2006 – Segunda semana Cuestión 1 (1 punto). En la práctica obligatoria del presente curso 2005/2006 se ha tenido que diseñar y desarrollar un algoritmo para resolver el juego del Su-doku. Codifique en java o en modula-2 un algoritmo iterativo que recorra el cuadrado de 3x3 casillas que corresponda a una casilla que ocupa las posiciones i,j del tablero. Cuestión 2 (2 puntos). Sea el famoso problema de la mochila. Se dispone de n objetos y una mochila. Para i= 1,2,…,n, el objeto i tiene un peso positivo wi y un valor positivo vi. La mochila puede llevar un peso que no sobrepase W. El objetivo es llenar la mochila de tal manera que se maximice el valor de los objetos almacenados, respetando la limitación de peso impuesta. Indique qué esquema o esquemas considera más adecuados para resolver este problema en los siguientes casos:

1. Los objetos se pueden fraccionar, luego se puede decidir llevar una fracción xi del objeto i, tal que 0 ≤ xi ≤ 1 para 1 ≤ i ≤ n.

2. Los objetos no se pueden fraccionar, por lo que un objeto puede o no ser añadido, pero en éste

último caso, sólo se añade 1. Además de nombrar el esquema o esquemas, explica el porqué de su elección, los aspectos destacados de cómo resolverías el problema y el coste asociado. No se piden los algoritmos. Cuestión 3 (3 puntos). Un dentista pretende dar servicio a n pacientes y conoce el tiempo requerido por cada uno de ellos, siendo ti , i= 1,2,…,n el tiempo requerido por el paciente i. El objetivo es minimizar el tiempo total que todos los clientes están en el sistema, y como el nº de pacientes es fijo, minimizar la espera total equivale a minimizar la espera media. Se pide:

1. Identificar una función de selección que garantice que un algoritmo voraz puede construir una planificación óptima. (0.5 puntos)

2. Hacer una demostración de la optimalidad de dicha función de selección. (2.5 puntos) Solución: están solucionados en el libro base de la asignatura, apartado 6.6.1, pág 231.

Problema (4 puntos). Dos socios que conforman una sociedad comercial deciden disolverla. Cada uno de los n activos que hay que repartir tiene un valor entero positivo. Los socios quieren repartir dichos activos a medias y, para ello, primero quieren comprobar si el conjunto de activos se puede dividir en dos subconjuntos disjuntos, de forma que cada uno de ellos tenga el mismo valor. La resolución de este problema debe incluir, por este orden: La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. (1 punto) 2. Estructuras de datos. (0,5 puntos) 3. Algoritmo completo a partir del refinamiento del esquema general. (2 puntos) 4. Estudio del coste ( 0,5 puntos)

Page 224: Examenes resueltos
Page 225: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2006 (Segunda Semana) Cuestión 1 (1 punto). En la práctica obligatoria del presente curso 2005/2006 se ha tenido que diseñar y desarrollar un algoritmo para resolver el juego del Su-doku. Codifique en java o en modula-2 un algoritmo iterativo que recorra el cuadrado de 3x3 casillas que corresponda a una casilla que ocupa las posiciones i,j del tablero. Solución: Se trataba de encontrar la relación entre las posiciones i,j del tablero y las posiciones de comienzo del cuadrado de 3x3 que les corresponde en el tablero del Su-doku 9x9. Supongamos que el tablero tiene como índices 0..8, 0..8 y que i y j son de tipo entero, la relación se puede establecer de la siguiente manera: int coordFilaInicioCuadrado = (i / 3) * 3; // división entera int coordColumnaInicioCuadrado = (j / 3) * 3; // división entera

ahora sólo queda hacer el recorrido: for (int k= coordFilaInicioCuadrado; k < coordFilaInicioCuadrado+3; k++)

for (int l= coordColumnaInicioCuadrado; l < coordColumnaInicioCuadrado+3; l++) procesar(tab[k][l]);

Cuestión 2 (2 puntos). Sea el famoso problema de la mochila. Se dispone de n objetos y una mochila. Para i= 1,2,…,n, el objeto i tiene un peso positivo wi y un valor positivo vi. La mochila puede llevar un peso que no sobrepase W. El objetivo es llenar la mochila de tal manera que se maximice el valor de los objetos almacenados, respetando la limitación de peso impuesta. Indique qué esquema o esquemas considera más adecuados para resolver este problema en los siguientes casos:

1. Los objetos se pueden fraccionar, luego se puede decidir llevar una fracción xi del objeto i, tal que 0 ≤ xi ≤ 1 para 1 ≤ i ≤ n.

2. Los objetos no se pueden fraccionar, por lo que un objeto puede o no ser añadido, pero en éste

último caso, sólo se añade 1. Además de nombrar el esquema o esquemas, explica el porqué de su elección, los aspectos destacados de cómo resolverías el problema y el coste asociado. No se piden los algoritmos. Solución: En el caso a) se puede utilizar el esquema voraz ya que existe una función de selección que garantiza obtener una solución óptima. La función de selección consiste en considerar los objetos en orden decreciente de vi/wi. El coste está en O(n log n), incluyendo la ordenación de los objetos. Ver página 227 del libro base de la asignatura. En el caso b) no se puede utilizar el esquema voraz ya que no existe una función de selección que garantice obtener una solución óptima. Al ser un problema de optimización se puede utilizar el esquema de ramificación y poda. Se podrían seleccionar los elementos en orden decreciente de vi/wi. Así, dado un determinado nodo, una cota superior del valor que se puede alcanzar siguiendo por esa rama se puede calcular suponiendo que la mochila la rellenamos con el siguiente elemento siguiendo el orden decreciente de vi/wi. El coste en el caso peor sería de orden exponencial, ya que en el árbol asociado al espacio de búsqueda, cada nodo tendrá dos sucesores que representarán si el objeto se añade o no a la mochila, es decir, O(2n). Sin embargo, sería de esperar que, en la práctica, el uso de la cota para podar reduzca el número de nodos que se exploran.

Page 226: Examenes resueltos

Cuestión 3 (3 puntos). Un dentista pretende dar servicio a n pacientes y conoce el tiempo requerido por cada uno de ellos, siendo ti , i= 1,2,…,n el tiempo requerido por el paciente i. El objetivo es minimizar el tiempo total que todos los clientes están en el sistema, y como el nº de pacientes es fijo, minimizar la espera total equivale a minimizar la espera media. Se pide:

1. Identificar una función de selección que garantice que un algoritmo voraz puede construir una planificación óptima. (0.5 puntos)

2. Hacer una demostración de la optimalidad de dicha función de selección. (2.5 puntos) Solución: están solucionados en el libro base de la asignatura, apartado 6.6.1, pág 231.

1. Cuando se sirve a los clientes por orden creciente de tiempos de servicio. 2. Sea 1 2, ,... nP p p p= cualquier permutación de enteros del 1 al n y sea i pis t= . Si se sirven clientes en el orden P, entonces el tiempo de servicio requerido por el i-ésimo cliente que haya que servir será si, y el tiempo total transcurrido en el sistema por todos los clientes es: ( ) ( ) ( )

( ) ( )

( )

1 1 2 1 2 3

1 2 3

1

...

1 2 ...

1n

kk

T P s s s s s s

ns n s n s

n k s=

= + + + + + +

= + − + − +

= − +∑

Supongamos ahora que P no organiza a los clientes por orden de tiempos creciente de servicio. Entonces se puede encontrar dos enteros a y b con a b< y a bs s> , si intercambiamos la posición de estos dos clientes, obtendremos un nuevo orden de servicio ´P que es simplemente el orden de P después de intercambiar los enteros a bp y p . El tiempo total transcurrido pasado en el sistema por todos los clientes si se emplea la planificación ´P es:

( ) ( ) ( ) ( )n

b a kk=1k a,b

T P = n - a+1 s + n - b+1 s + n - k +1 s≠

′ ∑

La planificación nueva es preferible a la vieja, porque: ( ) ( ) ( )( ) ( )( )

( )( ) 0a b b a

a b

T P T P = n - a+1 s s n - b+1 s s

b a s s

′− − + − =

− − >

Problema (4 puntos). Dos socios que conforman una sociedad comercial deciden disolverla. Cada uno de los n activos que hay que repartir tiene un valor entero positivo. Los socios quieren repartir dichos activos a medias y, para ello, primero quieren comprobar si el conjunto de activos se puede dividir en dos subconjuntos disjuntos, de forma que cada uno de ellos tenga el mismo valor. La resolución de este problema debe incluir, por este orden: (PROBLEMA 6.16 U.M., EDMA 470) Solución: 1. No se puede encontrar una función de selección que garantice, sin tener que reconsiderar decisiones, una elección de los activos que cumpla con la restricción del enunciado, por ello no se puede aplicar el esquema voraz. Tampoco se puede dividir el problema en subproblemas que al combinarlos nos lleven a una solución. Al no ser un problema de optimización, el esquema de exploración de grafos más adecuado es el esquema vuelta-atrás. Vuelta atrás es un recorrido en profundidad de un grafo dirigido implícito. En él una solución puede expresarse como una n-tupla [x1, x2, x3,… xn], donde cada xi, representa una decisión tomada en la etapa i-ésima, de entre un conjunto finito de alternativas.

Page 227: Examenes resueltos

Descripción algorítmica del esquema:

función vuelta-atrás(e: ensayo) si valido(e) entonces

dev e sino

listaEnsayos ← complecciones(e) mientras ¬ vacia(listaEnsayos) ∧ ¬resultado hacer

hijo ← primero(listaEnsayos) listaEnsayos ← resto(listaEnsayos) si condicionesDePoda(hijo) entonces

resultado ← vuelta-atrás(hijo) fsi

fmientras dev resultado

fsi ffunción

Otra posible descripción: función vuelta-atrás(v[1..k]: nTupla)

si solucion(v) entonces dev v

sino Para cada vector w k+1-prometedor hacer

si condicionesDePoda(w) entonces vuelta-atrás(w[1..k+1])

fsi fpara

fsi ffunción

En este caso, el espacio de búsqueda es un árbol de grado 2 y altura n+1. Cada nodo del i-ésimo nivel tiene dos hijos correspondientes a si el i-ésimo activo va a un socio o al otro.

Para poder dividir el conjunto de activos en dos subconjuntos disjuntos, de forma que

cada uno de ellos tenga el mismo valor, su valor debe ser par. Así, si el conjunto inicial de activos no tiene un valor par el problema no tiene solución.

2. Descripción de las estructuras de datos necesarias.

• El conjunto de activos y sus valores se representa en un array de enteros v=

[v1, v2, v3,… vn], donde cada vi representa el valor del activo i-ésimo. • La solución se representa mediante una array de valores x= [x1, x2, x3,… xn],

donde cada xi, podrá tomar el valor 1 o 2 en función de que el activo i-ésimo se asigne al subconjunto del un socio o del otro.

• Un array de dos elementos, suma, que acumule la suma de los activos de cada subconjunto.

3. Algoritmo completo a partir del refinamiento del esquema general.

En esta solución se sigue el segundo de los esquemas planteados en el apartado 2. Una posible condición de poda consistirá en que se dejarán de explorar aquellos nodos que verifiquen que alguno de los dos subconjuntos que se van construyendo tiene un valor mayor que la mitad del valor total.

función Solucion (k: entero; suma: array[1..2]) dev booleano

Page 228: Examenes resueltos

si (k = n) AND (suma[1] = suma [2]) entonces dev Verdadero sino dev Falso fsi ffuncion

función SeparacionSociosMitad (v: array[1..n], k: entero, suma: array[1..2], sumaTotal: entero) dev x: array[1..n]; separacion: boolean si Solucion (k, suma) entonces dev x, Verdadero sino para i desde 1 hasta 2 hacer x[k] ← i suma[i] ← suma[i] + v[k] si suma[i] <= (sumaTotal DIV 2) entonces si k < n entonces x ← SeparacionSociosMitad(v, k+1, suma, sumaTotal) fsi sino suma[i] ← suma[i] - v[k] fsi fpara fsi ffunción función ProblemaSeparacionSociosMitad (v: n-tupla) dev x: n-tupla; separacion: boolean para i desde 1 hasta n hacer sumaTotal ← sumaTotal + v[i] fpara si par(sumTotal) entonces dev SeparacionSociosMitad (v, 1, suma[0,0], sumaTotal) sino dev 0 fsi ffuncion Llamada inicial ProblemaSeparacionSociosMitad (v); 4. Estudio del coste del algoritmo desarrollado.

En este caso, el coste viene dado por el número máximo de nodos del espacio de búsqueda, esto es: T(n) ∈ O(2n)

Page 229: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2006 – Original Cuestión 1 (2 puntos). Demuestra que el tiempo de ejecución en función de n del siguiente fragmento de código está acotado superiormente por ( )2nΟ e inferiormente por ( )nΩ (1,5 puntos). Demuestra también su orden exacto de complejidad (0,5 puntos). para i desde 1 hasta n hacer

para j desde 1 hasta n div i hacer escribir “i,j,k”;

fpara fpara Cuestión 2 (2 puntos). Escribe la salida al realizar la llamada “pinta(5)”, dado el siguiente código (1,5 puntos): funcion pinta (int n)

si n>0 entonces escribir “n”; pinta (n-1); escribir “n-1”;

fsi Cuestión 3 (2 puntos). Dibuja cómo evolucionaría el siguiente vector al ordenarlo mediante el algoritmo de ordenación rápida (Quicksort). Indica únicamente cada una de las modificaciones que sufriría el vector. 6 5 1 2 3 4 7 8 9 Problema (4 puntos). Desarrollar un programa que compruebe si es posible que un caballo de ajedrez mediante una secuencia de sus movimientos permitidos recorra todas las casillas de un tablero NxN a partir de una determinada casilla dada como entrada y sin repetir ninguna casilla. Se pide:

1. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Razonar la respuesta y escribir el esquema general (0.5 puntos)

2. Indicar que estructuras de datos son necesarias (0.5 puntos) 3. Desarrollar el algoritmo completo en el lenguaje de programación que utilizaste para la práctica (2.5 puntos) 4. Hallar el orden de complejidad del algoritmo desarrollado (0.5 puntos)

Page 230: Examenes resueltos
Page 231: Examenes resueltos

Prueba Presencial

Ordinario

Septiembre de 2006

UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA

Programación III Código de asignatura (marcar con una X):

Sistemas: __ 402048 (plan viejo) __ 532044 (plan nuevo)

Gestión: __ 41204- (plan viejo) __ 542046 (plan nuevo) Duración: 2 horas

Material permitido: NINGUNO Apellidos: ___________________________________________________________________________________ DNI: _______________________ Nombre: ______________________________ Centro donde entregó la práctica: ____________________ e-mail: ___________________

Cuestión 1 (2 puntos). Demuestra que el tiempo de ejecución en función de n del siguiente fragmento de código está acotado superiormente por O(n2) e inferiormente por Ω(n) (1.5 puntos). Demuestra también su orden exacto de complejidad (0.5 puntos).

para i desde 1 hasta n hacer para j desde 1 hasta n div i hacer escribir “i,j,k”; fpara fpara

Supón que el coste de “escribir” es constante.

Solución: En primer lugar debemos plantear el tiempo de ejecución T(n) en función de n. Para ello, vamos a fijarnos en la instrucción barómetro (la instrucción que se ejecuta más veces) y vamos a contar cuántas veces se ejecuta. Puesto que todas las instrucciones tienen un coste constante, la complejidad del programa estará en el orden del número de veces que se ejecute la instrucción barómetro.

∑∑∑∑=== =

===n

i

n

i

n

i

in

j in

innT

111

/

1

1·1)(

∑=

n

i i1

1 es un sumatorio de n elementos menores o iguales que 1, por lo que su suma total será

menor que n. Por tanto, T(n) ≤ n·n, o en otras palabras, T(n) está acotado superiormente por n2: T(n)∈O(n2) como queríamos demostrar.

Por otra parte,∑=

n

i i1

1 es mayor que 1 y, por tanto T(n) ≥ n·1, o en otras palabras, T(n) está

acotado inferiormente por n: T(n)∈Ω(n) como queríamos demostrar.

Page 232: Examenes resueltos

Para demostrar el orden exacto es necesario saber cómo crece la serie∑=

n

i i1

1 . Para ello,

podemos aproximar la serie con la integral:

dxx

n

∫1

1 que corresponde al logaritmo natural de n. Por tanto, la serie crece tan rápidamente

como el ln(n). Así pues, se pueden encontrar dos constantes c y d tal que T(n) esté acotado superiormente por c·n·log(n) e inferiormente por d·n·log(n). En conclusión, el orden exacto de T(n) es n·log(n): T(n)∈θ(n log n) Cuestión 2 (2 puntos). Escribe la salida al realizar la llamada “pinta(5)”, dado el siguiente código (1.5 puntos): función pinta(int n) si n>0 entonces

escribir “n”; pinta(n-1); escribir “n-1”; fsi Demuestra el coste computacional de la función “pinta” suponiendo que “escribir” tiene coste constante (0.5 puntos). Solución: La salida sería: 5 4 3 2 1 0 1 2 3 4 Para calcular el coste planteamos una recurrencia con reducción del problema mediante sustracción:

n: tamaño del problemas a: número de llamadas recursivas b: reducción del problema en cada llamada recursiva n-b: tamaño del subproblema nk: coste de las instrucciones que no son llamadas recursivas

Recurrencia: c·nk si 0≤n<b T(n)= a·T(n-b)+c·nk si n≥b Θ(nk) si a<1 T(n)∈ Θ(nk+1) si a=1 Θ(an div b) si a>1

Page 233: Examenes resueltos

a=1; b=1; nk=1; k=0 Por tanto, T(n)∈ Θ(n) Cuestión 3 (2 puntos). Dibuja cómo evolucionaría el siguiente vector al ordenarlo mediante el algoritmo de ordenación rápida (Quicksort). Indica únicamente cada una de las modificaciones que sufriría el vector.

6 5 1 2 3 4 7 8 9 Solución: Si se toma como pivote el primer elemento:

6 5 1 2 3 4 7 8 94 5 1 2 3 6 7 8 94 3 1 2 5 6 7 8 92 3 1 4 5 6 7 8 92 1 3 4 5 6 7 8 91 2 3 4 5 6 7 8 9

Si se toma como pivote el elemento que ocupa la posición central, en este caso el primer pivote es el elemento que ocupa la posición quinta, que es el 3:

6 5 1 2 3 4 7 8 92 5 1 6 3 4 7 8 92 1 5 6 3 4 7 8 92 1 3 6 5 4 7 8 91 2 3 6 5 4 7 8 91 2 3 4 5 6 7 8 9

Problema (4 puntos). Desarrollar un programa que compruebe si es posible que un caballo de ajedrez mediante una secuencia de sus movimientos permitidos recorra todas las casillas de un tablero NxN a partir de una determinada casilla dada como entrada y sin repetir ninguna casilla. Se pide:

1. Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Razonar la respuesta y escribir el esquema general (0.5 puntos)

2. Indicar que estructuras de datos son necesarias (0.5 puntos) 3. Desarrollar el algoritmo completo en el lenguaje de programación que utilizaste para la

práctica (2.5 puntos) 4. Hallar el orden de complejidad del algoritmo desarrollado (0.5 puntos) Solución:

Page 234: Examenes resueltos

Un ejemplo de movimientos del caballo puede ser:

ξ

Elección razonada del algoritmo Hay varias razones para descartar tanto un esquema voraz como el de divide y vencerás. En el primero de los casos el conjunto de candidatos tendría necesariamente que ser el de las casillas del tablero. En tal caso, un movimiento en falso nos haría finalizar el algoritmo sin éxito u obligarnos a deshacer un movimiento ya realizado. No hay, por tanto, función de selección, por lo que el esquema voraz es incorrecto. Con respecto al esquema de divide y vencerás se observa que no hay forma de descomponer el problema en otros de menos tamaño sin que se desvirtúe el mismo. Descripción del esquema usado e identificación con el problema El esquema de vuelta atrás utiliza el retroceso como técnica de exploración de grafos. En este caso, el grafo es un árbol donde los nodos son tableros. No es pertinente utilizar ramificación y poda, puesto que no existe ningún parámetro que deba ser optimizado. El esquema general de vuelta atrás es el siguiente:

fun vuelta - atras(ensayo)si valido (ensayo) es una solucion entonces dev (ensayo)si no para cada hijo compleciones (ensayo)

si condiciones de poda (hijo) hacer v∈

uelta - atras(hijo) fsifpara

fsiffun

La particularización del esquema al problema del caballo puede hacerse así:

• Válido: Un ensayo será válido (solución) si no queda casilla alguna por visitar. • Compleciones: Se generarán tantos ensayos como casillas libres haya alcanzables directamente desde

la última casilla visitada. • Condiciones de poda: Si sólo se generan ensayos sobre casillas alcanzables no hay ninguna condición

de poda que añadir. Estructuras de datos Necesitamos manejar los siguientes elementos:

• La última posición que ha alcanzado el caballo. • El tablero con los movimientos efectuados. • El número de movimientos efectuados.

Para representar estos elementos se puede usar:

• Un par de enteros: i y j, que son las coordenadas de la última posición que ha alcanzado el caballo. • Una matriz de enteros donde cada posición representa una casilla y el valor indica en qué movimiento

ha pasado el caballo por la casilla. El valor 0 indica que esa casilla está libre. • Un entero, que indica el número de movimientos efectuados, siendo la solución al alcanzar todos ellos.

Page 235: Examenes resueltos

ensayo = tupla ultima-posicion = (i,j) tablero = [1..n, 1..n]de arreglo numero-movimientos = entero ftupla Algoritmo completo a partir del refinamiento del esquema general: Como hemos indicado antes, un ensayo consta de 3 elementos. La función válido utiliza únicamente uno de ellos para comprobar que el número de casillas ocupadas corresponde con el de casillas en el tablero. Ya veremos más adelante que esta comprobación es suficiente gracias a que las posiciones exploradas del árbol son únicamente aquellas legales y que, por tanto, son susceptibles de conducir a una solución. NOTA: Se ha hecho una pequeña modificación en la función insertar (recordemos que previamente vimos algo parecido con añadir) en la que se intercambian los parámetros para indicar el primero de ellos el elemento a añadir (en este caso w) y el segundo donde se añade. Además, se ha modificado está función para que devuelva una lista de ensayos, que no estaba incluida en la solución de dicho ejercicio. La única condición de retroceso posible es la del que el caballo haya alcanzado una posición tal que se encuentre rodeado de casillas ya recorridas y no pueda, por tanto, efectuar movimiento alguno sin repetir casilla. En este caso, el árbol no se sigue explorando y el algoritmo debe retroceder y buscar otra rama. Estrictamente hablando lo anterior no es una condición de poda. En el caso expuesto bastaría con generar todas las posibles compleciones (que serian 0 puestos que deben ser validas) y devolver una lista vacía para que la función retroceda. NOTA (del ejercicio): Al hablar de condiciones de poda nos referimos a que anticipamos que no hay solución por ese camino, no que hayamos llegado a un punto muerto. En ese sentido la condición de “caballo sin casillas libres a su alrededor” no es una condición de poda, ya que no es un criterio objetivo que anticipe a un camino erróneo. En el caso de este problema no hay en realidad condición de poda si no condición de retroceso y, por tanto, esta función no tiene sentido en esta implementación. Los movimientos posibles del caballo pueden verse en el dibujo anterior. Se puede ver que, si el caballo ocupa una posición (a,b), las casillas alcanzables son (a+i,b+j) en las que i,j ∈−2,−1,1,2 y tales que |i+j|=3. Con esta consideración, la generación de las casillas validas se puede hacer mediante un bucle con la condición anterior para formar los 8 nuevos movimientos posibles. Para crear los nuevos tableros a partir de un movimiento válido se utiliza la función de generar ensayo. Esta función crea una nueva variable ensayo y genera: 1. Un nuevo registro de última casilla ocupada con la posición obtenida del bucle. 2. Un nuevo tablero copiado del ensayo anterior al que se le añade la nueva posición en la que escribimos el correspondiente valor del número de movimientos efectuados. 3. Incrementamos en 1 el valor del número de movimientos efectuados que contenía al anterior ensayo. La función de compleciones adaptada a nuestro problema será: fun compleciones (e: ensayo) dev lista de ensayos lista ← lista vacía (i,j)←e.ultima-posición N ← e.numero-movs último-tablero ← e.tablero /* Generamos todas las posibles ramas */ para i ← −2 hasta 2 hacer para j ← −2 hasta 2 hacer si (abs(i)+ abs(j)=3) ^ (e.tablero[i,j] = 0) entonces nuevo-tablero ← último-tablero nuevo-tablero[i,j] ← N+1 nueva-posición ← (i,j) nuevo-ensayo ← <nuevo-tablero, nueva-posición, N+1> lista ← insertar (nuevo-ensayo, lista) fsi fpara fpara dev lista ffun

Page 236: Examenes resueltos

NOTA: De nuevo hacemos hincapié en que cada sentencia acaba en punto y coma, pero por evitar líos innecesarios no se hace en ninguna de las funciones anteriores. Por otro lado, algunas funciones podremos una variable (por ejemplo, e) como argumento o bien la propia estructura de datos (por ejemplo, ensayo), siendo indiferente su uso, debido a que la solución en todos los casos es idéntica. Digo esto, porque en la solución del ejercicio lo han puesto con el nombre de la estructura de datos en todas las funciones y en la solución escrita por mi es justamente el primer modo de poner los argumentos. Por último, un tablero es válido (solución) si hemos realizado 2N movimientos, con lo que la función quedaría así: fun válido (e: ensayo) dev boolean

dev (e.numero-movs = 2N ) ffun En la función principal, para recorrer la lista de compleciones, el esquema principal debe utilizar un bucle mientras … hacer. La función principal queda como sigue: fun saltocaballo (e: ensayo) si válido (e) entonces escribe ensayo sino lista ← compleciones (e) mientras ¬vacía (lista) hacer w ← primer elemento (lista) saltocaballo (w) lista ← resto (lista) fmientras fsi ffun Estudio del coste El estudio del coste en los algoritmos de búsqueda con retroceso es difícil de calcular con exactitud, ya que se desconoce el tamaño de lo explorado y sólo es posible en la mayoría de los casos dar una cota superior al tamaño de la búsqueda. Sin tener en cuenta las reglas de colocación del caballo en un tablero, 2N casillas pueden rellenarse con números entre 1 y 2n de ( )2 !n maneras posibles. La anterior aproximación es demasiado burda, ya que tenemos la información del número máximo de ramificaciones del árbol que es 8. Considerando esto el tamaño del árbol se puede acotar en

2

8n . Además, se puede precisar que no hay 8 posibles movimientos más que desde una parte del tablero. De cada 2n casillas, sólo desde 2n −8∗(n−2) es posible realizar 8 movimientos y además los últimos movimientos no tendrán prácticamente ninguna alternativa.

Page 237: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2006 Reserva Cuestión 1 (3 puntos). Hallar el coste de los siguientes algoritmos, siendo h(n,r,k) ∈ O(n2).

Cuestión 2 (1 punto). Explica cómo pueden ordenarse n valores enteros positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado. Explica las ventajas e inconvenientes de ese método. Cuestión 3 (1 punto). ¿Puede un grafo tener dos árboles de recubrimiento mínimo diferentes? En caso afirmativo poner un ejemplo. En caso negativo demostrarlo formalmente. Problema (5 puntos). Un repartidor de pizzas tiene que entregar K pedidos de diferente valor de recaudación como mucho hasta la ranura de tiempo concreta que tiene asignada en la tabla adjunta.

Pedido 1 2 3 4 5 6 7 8 9 Ranura 1 5 5 6 6 4 4 2 2 Recaudación 60 70 80 20 20 30 50 50 90

Si un pedido se entrega tarde la recaudación es 0. Construir un algoritmo que devuelva un plan de trabajo para el repartidor que maximice el beneficio. Aplíquelo al ejemplo detallando TODOS los pasos. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico. (0,5 puntos) 2. Algoritmo completo a partir del refinamiento del esquema general. (3,5 puntos) 3. Estudio del coste. (1 punto)

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 6 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 6, k-1); r ← r + uno (n DIV 6, k+1); r ← r + uno (n DIV 6, k+2); PARA i ← 1 HASTA 2*n HACER COMIENZO r ← h(n,r,i)+h(n,r-1,i); FIN DEVOLVER (r); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 8 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 8, k-1); r ← r + dos (n DIV 8, k+1); PARA i ← 1 HASTA n/2 HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 8, k+2); DEVOLVER (r); FIN FIN

Page 238: Examenes resueltos
Page 239: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2006 (Reserva) Cuestión 1 (3 puntos). Hallar el coste de los siguientes algoritmos, siendo h(n,r,k) ∈ O(n2).

El procedimiento uno tiene una instrucción condicional de coste constante. Dentro de la condición tiene: o bien una instrucción constante, que no tenemos en cuenta para el cálculo, o bien tres llamadas recursivas, ambas invocan la función con un tamaño n/6. //En el segundo y tercer caso de la llamada recursiva hay otra instrucción simple añadida. Un bucle en el que se repite 2n veces un cálculo consistente en llamar dos veces a una función h(n; r; i) de coste cuadrático. La expresión queda T(n) = T(n/6) + T(n/6) + T(n/6) + 2n(n2 + n2 )lo que equivale a que T(n) = 3T(n/6) + 4n3. Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk. lo que equivale a T(n) = 3T(n/6) + 4n3 y siendo 3 < 63 el coste es O(n3). a = 3, b = 6, k = 3 el segundo algoritmo: está formado por una instrucción condicional de coste constante cuyo cuerpo incluye secuencialmente: (i) una llamada recursiva de tamaño n/8, (ii) una instrucción simple, que no tenemos en cuenta para el cálculo, (iii) otra llama recursiva de tamaño n/8, (iv) un bucle en el que se repite n/2 veces un cálculo consistente en llamar dos veces a una función h(n; r; i) de coste cuadrático, /*más una instrucción simple*/, y por último (v) una instrucción simple que no tenemos en cuenta para el cálculo, y otra llamada recursiva de tamaño n/8. Sumando los términos nos sale T(n) = T(n/8)+T(n/8)+n/2* (2n2)+T(n/8), lo que equivale a T(n) = 3T(n/8) + 2n3 / 2 y siendo 3 < 8 3 el coste es O(n3). a = 3, b = 8, k = 3

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 6 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 6, k-1); r ← r + uno (n DIV 6, k+1); r ← r + uno (n DIV 6, k+2); PARA i ← 1 HASTA 2*n HACER COMIENZO r ← h(n,r,i)+h(n,r-1,i); FIN DEVOLVER (r); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 8 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 8, k-1); r ← r + dos (n DIV 8, k+1); PARA i ← 1 HASTA n/2 HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 8, k+2); DEVOLVER (r); FIN FIN

Page 240: Examenes resueltos

Cuestión 2 (1 punto). Explica cómo pueden ordenarse n valores enteros positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado. Explica las ventajas e inconvenientes de ese método. Suponiendo que el rango de los valores a ordenar es limitado, es decir, sabemos que por ejemplo el rango de números a ordenar va de 0 a 2000, podemos generar un vector de 2000 elementos de tipo entero que almacenará el número de ocurrencias de cada valor de la lista a ordenar en la posición del vector correspondiente. 1- El vector esta inicializado a 0 (O(n)). 2- Recorremos la lista de valores a ordenar (O(n)). Por cada valor i extraído de la lista, incrementamos el valor de la posición i del vector. 3- Recorremos el vector generado mostrando los valores generados en el paso anterior (2) y omitiendo aquellas posiciones del vector que contengan un 0. Las ventajas de esta ordenación es que el coste en tiempo de búsqueda es constante, sin embargo se requiere un determinado espacio de memoria que estará vacío. Ejemplo: n=1,5,12,15 V : vector[1..max(n(i))]For (i = 1; i <= n.length; i++)

V[n(i)] = n;

Indice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 valor 1 5 12 15 Cuestión 3 (1 punto). ¿Puede un grafo tener dos árboles de recubrimiento mínimo diferentes? En caso afirmativo poner un ejemplo. En caso negativo demostrarlo formalmente. Si. Siendo G=(N,A) un grafo conexo no dirigido en donde N es el conjunto de nodos y A es el conjunto de aristas. Suponiendo que cada arista posee una longitud no negativa. Encontrar un árbol de recubrimiento mínimo consiste en hallar un subconjunto T de las aristas de G tal que utilizando solamente las aristas de T, todos los nodos deben quedar conectados, y además la suma de las longitudes de las aristas de T debe ser tan pequeña como sea posible.

Page 241: Examenes resueltos

Problema (5 puntos). Un repartidor de pizzas tiene que entregar K pedidos de diferente valor de recaudación como mucho hasta la ranura de tiempo concreta que tiene asignada en la tabla adjunta.

Pedido 1 2 3 4 5 6 7 8 9 Ranura 1 5 5 6 6 4 4 2 2 Recaudación 60 70 80 20 20 30 50 50 90

Si un pedido se entrega tarde la recaudación es 0. Construir un algoritmo que devuelva un plan de trabajo para el repartidor que maximice el beneficio. Aplíquelo al ejemplo detallando TODOS los pasos. La resolución del problema debe incluir, por este orden: elección razonada del esquema algorítmico y esquema (0,5 puntos), algoritmo completo a partir del refinamiento del esquema general (3,5 puntos) y estudio del coste desarrollado (1 punto). Elección razonada del esquema algorítmico y esquema: El divide y vencerás queda descartado, ya que no parece posible dividir el problema en subproblemas iguales que puedan resolverse individualmente y posteriormente combinar las soluciones parciales para obtener la solución final. Se trata de un problema de optimización, por lo que podremos aplicar un voraz o un ramificación y poda. Cuenta con un conjunto de candidatos que serán los pedidos. Los pedidos deberán ser seleccionados de forma que puedan optimizar el beneficio que genera dicha ordenación y que se realicen dentro de la ranura de tiempo asignada. Se trata de un problema de planificación con optimización del beneficio, por lo que podemos utilizar el esquema voraz que aparece en el libro llamado Secuencia2. El esquema general de un algoritmo voraz es: fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← Seleccionar (C) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun Algoritmo genérico de secuencia 2: función Secuencia2 (d[1..n]):k; matriz[1..k] matriz j, F[0..n] iniciación p=min(n, maxd[i]|1≤ i ≤ n) para i 0 hasta p hacer j[i]=0; F[i]=i; fpara para i 1 hasta n hacer Orden decreciente de g k=buscar(min(p, d[i]); m=F[k]; si m ≠ 0 entonces j[m]=i; l=buscar(m-1); F(k)=F(l); fusionar(k, l); k 0 fsi para i 1 hasta p hacer si j[i]>0 entonces k=k+1 j[k]=j[i] fsi fpara

Page 242: Examenes resueltos

Coste del algoritmo: El coste de ordenar la tabla por orden decreciente de beneficio en el mejor tiempo posible es del orden de O(n log n).

fun repartidor (P[1..n], B[1..n]de nat)dev (pizza[1..n]de 1..n, k:1..n) var L[0..n], aux[1..n]de 0..n, partición: partición[0..n] l := P[1] para i = 2 hasta n hacer l := max (l, P[i]) fpara l:= min(n,l) partición := crear-particion3() aux[1..l]:= [0] para i = 0 hasta l hacer L[i]:= i fpara para i = 1 hasta n hacer c1:= buscar3(P[i], partición) m := L[c1] si m ≠ 0 entonces aux[m] = i c2:= buscar3(m-1, partición) fusionar3(c1, c2, partición); L[c1] = L[c2] fsi fpara Comprimir solución k:= 0 para i = 1 hasta l hacer si aux[i]>0 entonces k:= k+1 aux[k]:= aux[i] fsi fpara pizza[1..k]:= aux[1..k] ffun

Page 243: Examenes resueltos

ESCUELA TECNICA DE INGENIERIA INFORMATICA DE LA UNED (SISTEMAS Y GESTION)

Programación III – Diciembre 2.006 Convocatoria Extraordinaria

Tiempo: 2 horas. Ningún Material.

Cuestión 1 (2 puntos). Cuenta el número de operaciones elementales que efectúa el siguiente fragmento de código f en los casos mejor y peor, y a partir de estos resultados da su orden de complejidad, 푂 푓(푛) , y su orden exacto 휃 푓(푛) .

(1) para i desde 1 hasta n hacer (2) para j desde n hasta 푖 + 1 dec -1 hacer (3) si 푎[푗 − 1] > 푎[푗] entonces (4) 푡푒푚푝 = 푎[푗 − 1]; (5) 푎[푗 − 1] = 푎[푗]; (6) 푎[푗] = 푡푒푚푝 (7) fsi (8) fpara (9) fpara

Cuestión 2 (2 puntos). Explica cómo pueden ordenarse n valores positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado.

Cuestión 3 (2 puntos). Dado el grado de la figura, aplica el algoritmo de Dijkstra para hallar los caminos más cortos desde el nodo 1 hasta uno de los otros nodos, indicando en cada paso: nodos seleccionados, nodos no seleccionados, vector de distancias y vector de nodos precedentes.

10

13

26 7

5

8

Problema (4 puntos). Se desea grabar un CD de audio, de capacidad T, con canciones de una colección de n elementos, cuyas duraciones 푡 , … , 푡 cumplen: ∑ 푡 > 푇. Diseña un algoritmo que permita almacenar el máximo número de canciones en el espacio disponible. Puede suponerse que la colección de canciones está ordenada por longitud de menor a mayor.

La resolución de este problema debe incluir, por este orden:

1. Elección del esquema más apropiado, el esquema general y explicación de su aplicación al problema (1 punto).

2. Descripción de las estructuras de datos necesarias (0.5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2 puntos). 4. Estudio del coste del algoritmo desarrollado (0.5 puntos).

1

3 2

4 5

Page 244: Examenes resueltos
Page 245: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Diciembre 2006 Cuestión 1 (2 puntos). Cuenta el número de operaciones elementales que efectúa el siguiente fragmento de código f en los casos mejor y peor, y a partir de estos resultados da su orden de complejidad, Ο((f)n), y su orden exacto Θ((f)n). (1) para i desde 1 hasta n hacer (2) para j desde n hasta i+1 dec -1 hacer (3) si a[j−1]>a[j] entonces (4) temp=a[j−1]; (5) a[j−1]=a[j]; (6) a[j]=temp (7) fsi (8) fpara (9) fpara

Para obtener el tiempo de ejecución, calcularemos primero el número de operaciones elementales (OE) que se realizan: En la línea (1) se ejecutan 2 OE (una asignación y una comparación) en cada una de las iteraciones del bucle más otras 2 al final, cuando se efectúa la salida del FOR. Igual ocurre con la línea (2), también con 3 OE (una asignación, una suma y una comparación) por iteración, más otras 3 al final del bucle. En la línea (3) se efectúa una condición, con un total de 4 OE (una diferencia, dos accesos a un vector, y una comparación). Las líneas (4) a (6) sólo se ejecutan si se cumple la condición de la línea (3), y realizan un total de 9 OE: 3, 4 y 2 respectivamente. Con esto: En el caso mejor para el algoritmo la condición de la línea (3) será siempre falsa, y no se ejecutarán nunca las líneas (4), (5) y (6). Así, el bucle más interno realizará (n–i) iteraciones, cada una de ellas con 4 OE (línea 3), más las 3 OE de la línea (2). Por tanto, el bucle más interno realiza un total de

1 1(4 3) 3 7 1 3 7( ) 3

n n

j i j in i

= + = +

⎛ ⎞ ⎛ ⎞+ + = + = − +⎜ ⎟ ⎜ ⎟

⎝ ⎠ ⎝ ⎠∑ ∑

OE, siendo el 3 adicional por la condición de salida del bucle. A su vez, el bucle externo repetirá esas 7(n–i)+3 OE en cada iteración, lo que hace que el número de OE que se realizan en el algoritmo sea:

2

1

7 3( ) (7( ) 3) 2 2 12 2

n

i

T n n i n n=

⎛ ⎞= − + + + = + −⎜ ⎟⎝ ⎠∑

En el caso peor, la condición de la línea (3) será siempre verdadera, y las líneas (4), (5) y (6) se ejecutarán en todas las iteraciones. Por tanto, el bucle más interno realiza

1(4 9 3) 3 16( ) 3

n

j in i

= +

⎛ ⎞+ + + = − +⎜ ⎟

⎝ ⎠∑

Page 246: Examenes resueltos

OE. El bucle externo realiza aquí el mismo número de iteraciones que en el caso anterior, por lo que el número de OE en este caso es:

2

1

( ) (16( ) 3) 2 2 8 10 2n

i

T n n i n n=

⎛ ⎞= − + + + = + +⎜ ⎟⎝ ⎠∑

En el caso medio, la condición de la línea (3) será verdadera con probabilidad 1/2. Así, las líneas (4), (5) y (6) se ejecutarán en la mitad de las iteraciones del bucle más interno, y por tanto realiza

1

1 23(4 9) 3 3 ( ) 32 2

n

j in i

= +

⎛ ⎞+ + + = − +⎜ ⎟

⎝ ⎠∑

OE. El bucle externo realiza aquí el mismo número de iteraciones que en el caso anterior, por lo que el número de OE en este caso es:

2

1

23 23 31( ) ( ) 3 2 2 22 4 4

n

i

T n n i n n=

⎛ ⎞⎛ ⎞= − + + + = +⎜ ⎟⎜ ⎟⎝ ⎠⎝ ⎠∑

b) Como los tiempos de ejecución en los tres casos son polinomios de grado 2, la complejidad del algoritmo es cuadrática, independientemente de qué caso se trate. Obsérvese cómo hemos analizado el tiempo de ejecución del algoritmo sólo en función de su código y no respecto a lo que hace, puesto que en muchos casos esto nos llevaría a conclusiones erróneas. Debe ser a posteriori cuando se analice el objetivo para el que fue diseñado el algoritmo. En el caso que nos ocupa, un examen más detallado del código del procedimiento nos muestra que el algoritmo está diseñado para ordenar de forma creciente el vector que se le pasa como parámetro, siguiendo el método de la Burbuja. Lo que acabamos de ver es que sus casos mejor, peor y medio se producen respectivamente cuando el vector está inicialmente ordenado de forma creciente, decreciente y aleatoria. Cuestión 2 (2 puntos). Explica cómo pueden ordenarse n valores positivos en tiempo lineal, sabiendo que el rango de dichos valores es limitado. (Pág 79) Suponiendo que el rango de los valores a ordenar es limitado, es decir, sabemos que por ejemplo el rango de números a ordenar va de 0 a 2000, podemos generar un vector de 2000 elementos de tipo entero que almacenará el número de ocurrencias de cada valor de la lista a ordenar en la posición del vector correspondiente. 1- El vector esta inicializado a 0 (O(n)). 2- Recorremos la lista de valores a ordenar (O(n)). a. Por cada valor i extraído de la lista, incrementamos el valor de la posición i del vector. 3- Recorremos el vector generado mostrando los valores generados en el paso anterior (2) y omitiendo aquellas posiciones del vector que contengan un 0.

Page 247: Examenes resueltos

Cuestión 3 (1 puntos). Dado el grado de la figura, aplica el algoritmo de Dijkstra para hallar los caminos más cortos desde el nodo 1 hasta uno de los otros nodos, indicando en cada paso: nodos seleccionados, nodos no seleccionados, vector de distancias y vector de nodos precedentes.

Distancias desde 1 Nodo Precedente

Paso Nodo Seleccionado

Nodo No Seleccionado 2 3 4 5 2 3 4 5

Inicializa 1 2,3,4,5 13 26 ∞ 5 1 1 1 1 1 1,5 2,3,4 13 26 13 5 1 1 5 1 2 1,5,4 3,5 13 20 13 5 1 4 5 1 3 1,5,4,3 2 13 20 13 1 1 4 5 1 Problema (4 puntos). Se desea grabar un CD de audio, de capacidad T, con canciones de una colección

de n elementos, cuyas duraciones t1,…, tn cumplen: 1

n

ii

t n=

>∑ . Diseña un algoritmo que permita

almacenar el máximo número de canciones en el espacio disponible. Puede suponerse que la colección de canciones está ordenada por longitud de menor a mayor. Solución: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). Ver explicación en el ejercicio 1 de enero 2005, se trata de un problema de optimización, por lo tanto descarto divide y vencerás y vuelta atrás. Me queda saber si puedo encontrar una función de selección para decidirme por un esquema voraz. Eligiendo a los elementos por orden creciente de longitud, obtenemos una solución óptima, así puedo descartar ramificación y poda. fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← Seleccionar (C) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). Ver explicación en el ejercicio 1 de enero 2005.

Page 248: Examenes resueltos

3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (2 puntos).

public class SeleccionFicheros Fichero ficheros[]; //Array que almacena objetos fichero Fichero disco[]; //Array que almacenará la solución con los objetos escogidos int n; //numero total de ficheros int capacidadDisco; //Tamaño total del disco public SeleccionFicheros(Fichero ficheros[], int capacidadDisco) this.ficheros = ficheros; disco = new Fichero[capacidadDisco]; this.capacidadDisco = capacidadDisco; n = ficheros.length; /** * Calcula para cada fichero el cociente de la prioridad y el tamaño de cada * fichero y los ordena de mayor a menor según este cociente. Posteriormente * los introduce en el disco siguiendo este orden hasta que no quepan en el * espacio restante. */ public void crearDisco() int capacidadRestante = capacidadDisco; int contador = 0; //indice del array donde vamos almacenando los ficheros en disco ordenar(); imprimirFicheros(); for (int i = 0; i < n; i++) if (ficheros[i].getTam() <= capacidadRestante) disco[contador++] = ficheros[i]; capacidadRestante -= ficheros[i].getTam(); /** * Algoritmo que ordena el array ficheros por el método de la burbuja */ private void ordenar() Fichero temp; for (int i = 0; i < n - 1; i++) for (int j = i + 1; j < n; j++) if (ficheros[j].getRelacion() > ficheros[i].getRelacion()) temp = ficheros[i]; ficheros[i] = ficheros[j]; ficheros[j] = temp; /** * Muestra el contenido del disco por pantalla */ public void imprimir() for (int i = 0; i < capacidadDisco; i++) if (disco[i] != null) System.out.println(disco[i].toString()); /** * Muestra el contenido del array de ficheros */ public void imprimirFicheros() for (int i = 0; i < n; i++) if (ficheros[i] != null) System.out.println(ficheros[i].toString());

Page 249: Examenes resueltos

5. Estudio del coste (0,5 puntos).

En nuestra implementación la complejidad temporal viene dada por:

• Ordenar el array de ficheros mediante el algoritmo de la burbuja con complejidad O(n2). • Insertar los ficheros en el disco con complejidad O(n).

En conclusión, el orden de complejidad del algoritmo completo vendrá marcado por la mayor de estas complejidades parciales y corresponde a la ordenación del vector.

Complejidad total: O(n2).

public class Fichero private String identificador; private float tam; private int prioridad; private float relacion; //Cociente prioridad-tamaño public Fichero(String identificador, float tam, int prioridad) this.identificador = identificador; this.tam = tam; this.prioridad = prioridad; relacion = prioridad / tam; public String toString() return "Identificador= " + identificador + " Tamaño= " + tam + " Prioridad= " + prioridad + " Relacion= " + getRelacion(); public String getIdentificador() return identificador; public int getPrioridad() return prioridad; public float getRelacion() return relacion; public float getTam() return tam;

Page 250: Examenes resueltos
Page 251: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2007 – Primera semana Cuestión 1 (2 puntos). Implementa en Java o Módula-2 la función de estimación de la cota en el problema del n-puzzle (práctica de este curso). Cuestión 2 (2 puntos). Escribir en pseudocódigo una función recursiva de búsqueda binaria en un vector, suponiendo que en algunos casos el elemento no está en el vector (1 punto). Demuestra el coste que tiene la función implementada (1 punto). Cuestión 3 (2 puntos). Dado un vector [ ]C 1..n de números enteros distintos, y un

número entero S, se pide plantear un programa de complejidad en ( )nlognΘ que determine si existen o no dos elementos de C tales que su suma sea exactamente S. En caso de utilizar algoritmos conocidos no es necesario codificarlos. (Resuelto en Estructuras de datos y métodos algorítmicos pag 338) Problema (4 puntos). Hoy es un día duro para el taller Sleepy. Llegan las vacaciones y a las 8:00 de la mañana n clientes han pedido una revisión de su coche. Como siempre, todos necesitan que les devuelvan el coche en el menor tiempo posible. Cada coche necesita un tiempo de revisión ri y al mecánico le da lo mismo por cuál empezar: sabe que en revisar todos los coches tardará lo mismo independientemente del orden que elija. Pero al jefe de taller no le da lo mismo, la satisfacción de sus clientes es lo que importa: es mejor tener satisfechos al mayor número de ellos. Al fin y al cabo, la planificación la hace él y, evidentemente, un cliente estará más satisfecho cuanto menos tarden en devolverle el coche. Implementar un programa que decida el orden en el que revisar uno a uno los coches para maximizar la satisfacción de los clientes de Sleepy. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Demuestra que el problema se puede resolver con el esquema elegido (0,5 puntos). 3. Estructuras de datos (0,5 puntos). 4. Algoritmo completo a partir del refinamiento del esquema general (1,5 puntos). 5. Estudio del coste (1 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 252: Examenes resueltos
Page 253: Examenes resueltos

[ ]( )[ ]

[ ] [ ]

( )[ ] [ ]( )

2

fun binrec T i..j ,x

Búsqueda binaria de x en la submatriz T i..j

con la seguridad de que T i -1 < x T j

si i j entonces devolver ik i j

si x T k entonces devolver binrec T i..k ,x

sino dev

=

← + ÷

[ ]( )1

olver binrec T k ..j ,x

fsiffun

+

RESPUESTAS EXAMEN Programación III. Febrero 2007 (Primera Semana) Cuestión 1 (2 puntos). Implementa en Java o Módula-2 la función de estimación de la cota en el problema del n-puzzle (práctica de este curso). Cuestión 2 (2 puntos). Escribir en pseudocódigo una función recursiva de búsqueda binaria en un vector, suponiendo que en algunos casos el elemento no está en el vector (1 punto). Demuestra el coste que tiene la función implementada (1 punto).

[ ]( )[ ]

[ ]( )

fun busquedabin T 1..n ,x

si n = 0 ó x >T n entonces devolver n+1

sino devolver binrec T 1..n ,x

Para demostrar el coste utilizo la ecuación de recurrencia:

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Donde a = 1, b = 2, k = 0 → ( ) log nΘ

Page 254: Examenes resueltos

Cuestión 3 (2 puntos). Dado un vector [ ]C 1..n de números enteros distintos, y un número entero S,

se pide plantear un programa de complejidad en ( )nlognΘ que determine si existen o no dos elementos de C tales que su suma sea exactamente S. En caso de utilizar algoritmos conocidos no es necesario codificarlos. (Resuelto en Estructuras de datos y métodos algorítmicos pag 338) Resuelvo el problema de la siguiente manera, primero ordeno el vector C y segundo para cada elemento x de C buscar, utilizando búsqueda binaria el entero S - x . Si alguna de las búsquedas tiene éxito habremos encontrado dos elementos de C que suman S. Utilizando la ordenación por fusión el coste del primer paso está en ( )nlognΘ , y el coste del segundo

paso está en ( )nlognΘ . En el peor caso se hacen n búsquedas binarias de coste ( )lognΘ cada una de

ellas, por lo tanto el coste total es ( )nlognΘ .

[ ]( )[ ]

( )

[ ]

1 2

1 2 1

1.. , : : , , :

: ; ; : ; : ;

funcion buscar dos C n de ent S ent dev existe bool x x ent

var V 1..n de ent

V C ordenar Vj := 1; existe := falsomientras j n ¬existe hacer

x V j x S x

exis

=

≤ ∧

= = −

( )

2: , ,1,

: : 1;

te, p busqueda binaria V x n

existe existe p j no puede usarse el mismo numero dos vecesj j

fmientrasffuncion

= −

= ∧ ≠

= +

Page 255: Examenes resueltos

Problema (4 puntos). Hoy es un día duro para el taller Sleepy. Llegan las vacaciones y a las 8:00 de la mañana n clientes han pedido una revisión de su coche. Como siempre, todos necesitan que les devuelvan el coche en el menor tiempo posible. Cada coche necesita un tiempo de revisión ri y al mecánico le da lo mismo por cuál empezar: sabe que en revisar todos los coches tardará lo mismo independientemente del orden que elija. Pero al jefe de taller no le da lo mismo, la satisfacción de sus clientes es lo que importa: es mejor tener satisfechos al mayor número de ellos. Al fin y al cabo, la planificación la hace él y, evidentemente, un cliente estará más satisfecho cuanto menos tarden en devolverle el coche. Implementar un programa que decida el orden en el que revisar uno a uno los coches para maximizar la satisfacción de los clientes de Sleepy. Elección razonada del esquema algorítmico más eficiente para resolver el problema. Se trata de un problema de optimización, por lo tanto descarto el esquema de divide y vencerás, para este problema se puede encontrar una función de selección que lo resuelva, de esta manera descarto el esquema de ramificación y poda, debemos elegir a los clientes por orden creciente de tiempo de finalización, este problema se corresponde con el problema de minimización del tiempo en el sistema. Esquema general: fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← elemento que maximiza objetivo (x) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun Estructuras de datos: Tres vectores de enteros, un vector booleano y la función auxiliar ordenar índices. Algoritmo completo a partir del refinamiento del esquema general fun taller (C[1..n]nat, D[1..n]nat) dev sol[1..n] bool

var F[1..n]nat ; I[1..n]1..n ; para i=1 hasta n hacer F[i]:= C[i]+D[i]; sol[i]:= falso; fpara I:= ordenar-indices(F) sol[I[1]]:= cierto; final := F[I[1]]; para i=2 hasta n hacer si C[I[i]]≥ final entonces sol[I[i]]:= cierto; final := F[I[i]]; fsi fpara ffun fun ordenar-indices(V[1..n])dev indice [1..n]1..n merge-indice(V,indice,1,n) ffun Estudio del coste El bucle voraz es de complejidad lineal respecto al número de clientes y el orden de complejidad del algoritmo completo corresponde al de la ordenación del vector de tiempos finales ( )nlognΘ .

Page 256: Examenes resueltos
Page 257: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2007 – Segunda semana Cuestión 1 (2 puntos). ¿Cual es el tamaño del problema, n, que determina el orden de complejidad del siguiente procedimiento? (0.5 puntos). Calcula el orden de complejidad del algoritmo en función de dicho tamaño (1.5 puntos). tipo vector = array de enteros; procedimiento examen(var a:vector; prim,ult, x: entero): boolean;

var mitad: entero; si (prim >= ult) entonces

devolver a[ult] = x si no

mitad = (prim + ult) div 2; si (x = a[mitad]) entonces

devolver cierto si no si (x < a[mitad]) entonces

devolver examen(a, prim, mitad-1, x) si no

devolver examen(a, mitad+1, ult, x) fsi

fsi

Cuestión 2 (2 puntos). Escribe en Java el algoritmo principal del esquema de ramificación y poda utilizado en la práctica del presente curso (no es necesario implementar las funciones auxiliares). Cuestión 3 (2 puntos). Aplica el algoritmo de Kruskal al siguiente grafo indicando claramente en cada paso qué arista se selecciona, la evolución de las componentes conexas y la evolución de la solución.

Problema (4 puntos). Disponemos de un conjunto A de n números enteros (tanto positivos como negativos) sin repeticiones almacenados en una lista. Dados dos valores enteros m y C, siendo m < n se desea resolver el problema de encontrar un subconjunto de A compuesto por exactamente m elementos y tal que la suma de los valores de esos m elementos sea C. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste (1 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 258: Examenes resueltos
Page 259: Examenes resueltos

Programacion IIIFebrero de 2007

NOMBRE:

APELLIDOS:

DNI:

Cuestion 1 (2 puntos)¿ Cual es el tamano del problema, n, que determina el orden de complejidad delsiguiente procedimiento? (0.5 puntos). Calcula el orden de complejidad del algoritmoen funcion de dicho tamano (1.5 puntos).

tipo vector = array de enteros;

procedimiento examen(var a:vector; prim,ult, x: entero): boolean;

var

mitad: entero;

(1) si (prim >= ult) entonces

(2) devolver a[ult] = x

(3) si no

(4) mitad = (prim + ult) div 2;

(5) si (x = a[mitad]) entonces

(6) devolver cierto

(7) si no si (x < a[mitad]) entonces

(8) devolver examen(a, prim, mitad-1, x)

(9) si no

(10) devolver examen(a, mitad+1, ult, x)

(11) fsi

(12) fsi

Solucion

a) n = (ult - prim)+1

b) Contando las instrucciones tenemos que si se cumple la condicion de la lınea (1)el coste es cte.. Si se va por la lınea (3), puede irse por la la linea (6) (coste cte), porla lınea (8) (coste t(n/2) + cte) o por la lınea (10) (coste t(n/2) + cte). Por tanto,T(n) = T(n/2) + cte.

Planteamos la recurrencia con reduccion del problema mediante division:

n: tamano del problema a: numero de llamadas recursivas n/b: tamano del subpro-blema cnk: coste de las instrucciones que no son llamadas recursivas

T (n) =

cnk si 0 ≤ n < baT (n/b) + cnk si n ≥ b

entonces

T (n) ∈

Θ(nk) si a < bk

Θ(nklogn) si a = bk

Θ(nnlogba) si a > bk

En nuestro caso, tenemos que los valores son a = 1, b = 2, cnk = cte, k = 0. d Dedonde T(n) ∈ Θ(logn).

Page 260: Examenes resueltos

Cuestion 2 (2 puntos)Escribe en Java el algoritmo principal del esquema de ramificacion y poda utili-zado en la practica del presente curso (no es necesario implementar las funcionesauxiliares).

Solucion:

La implementacion mas sencilla es dejar los nodos solucion dentro de la cola deprioridad. Cuando el primero de la cola sea solucion entonces hemos encontrado lasolucion optima porque el resto de nodos proporcionan una estimacion que aun enel mejor de los casos serıa peor:

public class MejorPrimero implements SearchAlgorithm

public Solution SearchSolution(Node nodoInicial)

Solution solucion;

Queue<Node> cola = new PriorityQueue<Node>();

cola.add(nodoInicial);

while(!cola.isEmpty() )

Node nodo = cola.poll();

if( nodo.isSolution() )

return nodo.getSolution();

else

for(Node nodoHijo:nodo.generatePossibleChildren())

cola.offer( nodoHijo );

return null;

Sin embargo, la solucion anterior tiene el problema de que todos los nodos (incluidasalgunas soluciones) se guardan en memoria (en la cola de prioridad) aun sabiendoque muchos no pueden proporcionar la solucion optima. Por tanto, es posible refinarel algoritmo anterior para ir eliminando de la cola de prioridad todos los nodos quepodamos ir descartando. Para descartar nodos, primero tenemos que encontrar unasolucion que se convierte en la solucion de referencia. Todos los nodos ya existentescon una estimacion peor se eliminan de la cola (metodo depurar) y todos los nuevosnodos con una estimacion peor ya no se meten en la cola. Esta version necesita menosmemoria, pero puede tener mayor coste computacional puesto que hay que recorrerla cola cada vez que encontramos una nueva solucion. Por otro lado, mantener lacola tiene menos coste porque en general contendra menor numero de nodos.

Page 261: Examenes resueltos

public class RamificacionYPoda implements SearchAlgorithm

public Solution searchSolution(Node nodoInicial)

Queue<Node> cola = new PriorityQueue<Node>();

cola.add(nodoInicial);

// Soluci’on inicial

int costeMejor = Integer.MAX_VALUE;

while(!cola.isEmpty() )

Node nodo = cola.poll();

if( nodo.isSolution() )

int costeReal = nodo.getCost();

if( costeReal < costeMejor )

costeMejor = costeReal;

solucion = nodo.getSolution();

depurar(cola, costeMejor);

else

for(Node nodoHijo:nodo.generatePossibleChildren())

int cota=nodoHijo.calculateEstimatedCost();

if(cota < costeMejor)

cola.offer( nodoHijo );

return solucion;

private void depurar(Queue<Node> cola, int costeMejor)

Iterator it = cola.iterator();

List<Node> depurationList = new ArrayList<Node>();

while(it.hasNext())

Node node = (Node) it.next();

if(node.calculateEstimatedCost()>costeMejor)

depurationList.add(node);

cola.removeAll(depurationList);

Cuestion 3 (2 puntos)Aplica el algoritmo de Kruskal al siguiente grafo indicando claramente en cada pasoque arista se selecciona, la evolucion de las componentes conexas y la evolucion dela solucion.

Page 262: Examenes resueltos

1

2

3 4

5 6

3

6

1 2 9

84

10

7

5

Se ordenan las aristas de menor a mayor coste:

Arista Evolucion de las Evolucionseleccionada componentes conexas de la solucion

1,2,3,4,5,6 ∅(3,5) 1,2,3,5,4,6 (3,5)(2,5) 1,2,3,5,4,6 (3,5), (2,5)(1,3) 1,2,3,5,4,6 (3,5), (2,5), (1,3)(1,2) Rechazada∗ (3,5), (2,5), (1,3)(2,3) Rechazada∗ (3,5), (2,5), (1,3)(2,4) 1,2,3,5,4,6 (3,5), (2,5), (1,3), (2,4)(5,6) 1,2,3,5,4,6 (3,5), (2,5), (1,3), (2,4), (5,6)

(*: ambos nodos en una misma particion)

Problema (4 puntos)Disponemos de un conjunto A de n numeros enteros (tanto positivos como negativos)sin repeticiones almacenados en una lista. Dados dos valores enteros m y C, siendom < n se desea resolver el problema de encontrar un subconjunto de A compuestopor exactamente m elementos y tal que la suma de los valores de esos m elementossea C.

La resolucion de este problema debe incluir, por este orden:

1. Eleccion del esquema mas apropiado, el esquema general y explicacion de suaplicacion al problema (0.5 puntos).

2. Descripcion de las estructuras de datos necesarias (0.5 puntos).

3. Algoritmo completo a partir del refinamiento del esquema general (2.5 puntos).

4. Estudio del coste del algoritmo desarrollado (1 punto).

Seleccion del esquema algorıtmico Se trata de una busqueda, no de una op-timizacion, por lo que no son aplicables el esquema voraz ni el de ramificacion ypoda. Tampoco se puede dividir el problema en subproblemas que se resuelvan conexactamente con el mismo procedimiento.

Tenemos que recorrer un arbol de soluciones candidatas, pero siguiendo aquellasramas que tengan opcion de convertirse en una solucion (k-prometedoras) por loque el esquema de vuelta atras es adecuado. Tambien es valido un recorrido delarbol de soluciones en profundidad, siempre que el recorrido se detenga en el nivelcorrespondiente a m.

Page 263: Examenes resueltos

Dependiendo de la representacion del ensayo y de la estrategia de ramificacion (ge-neracion de hijos) tenemos al menos dos aproximaciones para el esquema de vueltaatras.

En una primera aproximacion (que llamaremos A) podrıa representarse el ensayocomo un vector de m enteros y los descendientes de un nodo de nivel k serıan todaslos valores no tomados anteriormente. Ası del nodo raız tendrıamos n opciones parael nivel 1 del arbol, en el nivel 2 tendrıamos n(n − 1) hijos, etc. hasta el nivel m.Como se vera mas adelante, en el caso peor que es cuando m tiende a n, el numerode nodos del arbol es n!.

La segunda aproximacion (que llamaremos B) es mas correcta y consistirıa en re-presentar el ensayo como un vector de n booleanos. De este modo los descendientesde un nodo de nivel k serıan las opciones de tomar o no el valor k + 1 del vectorde entrada. Es decir siempre se tendrıan dos opciones. Cuando m tiende a n, elnumero de nodos serıa 2n que es mejor que n! Lo que esta ocurriendo basicamente,es que la segunda alternativa evita considerar permutaciones, es decir, tomar losmismos numeros pero en orden diferente. Ademas esta segunda opcion es mas facilde implementar.

A continuacion mostraremos la implementacion de las dos alternativas. Considera-mos los siguientes apartados para cada una de las alternativas:

Alternativa A

1. Esquema general

fun vuelta-atras(e: ensayo) dev (booleano, ensayo)

si valido(e) entonces

dev (cierto,e)

sino

listaensayos <-- compleciones(e)

mientras no vacia(listaensayos) y no es_solucion hacer

hijo <-- primero(listaensayos)

listaensayos <-- resto(listaensayos)

si esprometedora(hijo) entonces

(es_solucion,solucion) <-- vuelta-atras(hijo)

fsi

fmientras

dev (es_solucion, solucion)

fsi

ffun

esprometedora comprueba si se cumplen las condiciones de poda, es decirsera una funcion que compruebe que el numero de sumandos ya selecciona-dos es menor que m.

compleciones es una funcion que considera todos los numero que aun no hansido probados como siguiente elemento.

valido comprueba que se haya alcanzado una solucion.

2. estructuras de datos

Tipo ensayo=

candidatos: vector de enteros //numeros que aun no se han probado

Page 264: Examenes resueltos

solucion: vector de enteros //numeros de la posible solucion

suma: entero // valor alcanzado hasta ese momento

num_sumados: entero // cantidad de numeros que ya se han sumado

3. algoritmo completo

funcion compleciones(e: ensayo) dev lista_compleciones

lista_compleciones <-- lista_vacia

para cada i en e.candidatos hacer

nuevo_ensayo <-- e

eliminar(nuevo_ensayo.candidatos, i)

anadir(nuevo_ensayo.solucion, i)

nuevo_ensayo.suma <-- e.suma + i

nuevo_ensayo.num_sumados <-- e.num_sumados + 1

lista_compleciones <-- anadir(lista_compleciones, nuevo_ensayo)

fpara

dev lista_compleciones

funcion esprometedora(e:ensayo) dev booleano

si (e.num_sumados < m) entonces

dev cierto

si no

dev falso

funcion valido(e:ensayo) dev booleano

si (e.suma = C) y (e.num_sumados = m) entonces

dev cierto

si no

dev falso

4. Complejidad del algoritmo Una cota superior al tiempo de ejecucion serıa elnumero de nodos del arbol, es decir las combinaciones de n elementos tomadosde m en m, multiplicado por el numero de posibles permutaciones, ya que estasno se excluyen:

T (n, m) =

(

nm

)

m! =n!

(m − n)!m!m! =

n!

(n − m)!= n(n − 1) · · · (n − m + 1)

Llegamos al mismo resultado calculando el numero de hijos de cada nivel delarbol: el numero de hijos de primer nivel es n, el numero de hijos del segundonivel es n(n − 1), hasta llegar al nivel (n − m + 1), cuyo numero de hijos esn(n − 1) · · · (n − m + 1).

Podemos observar que

si m → n =⇒ T (n) ∈ O(n!)si m → 1 =⇒ T (n) ∈ O(n)

Alternativa B

1. Esquema general

fun vuelta-atras(e: ensayo, k ) dev (booleano, ensayo)

// e es k-prometedor

si K=limite entonces

dev (cierto,e)

Page 265: Examenes resueltos

sino

listaensayos <-- compleciones(e,k+1)

mientras no vacia(listaensayos) y no es_solucion hacer

hijo <-- primero(listaensayos)

listaensayos <-- resto(listaensayos)

si esprometedora(hijo,k+1) entonces

(es_solucion,solucion) <-- vuelta-atras(hijo,k+1)

fsi

fmientras

dev (es_solucion, solucion)

fsi

ffun

En la llamada inicial a vuelta-atras, todas las posiciones de e.candidatos seinicializan a true y k toma el valor 0.

2. Estructuras de datos

datos: vector de enteros //lista de numeros de entrada

Tipo ensayo=

candidatos: vector de booleanos //indica si el numero de cada posicion

// se incluye en la solucion

suma: entero // valor alcanzado hasta ese momento

num_sumados: entero // cantidad de valores true de los candidatos

3. algoritmo completo

funcion compleciones(e: ensayo, k:entero) dev lista_compleciones

lista_compleciones <-- lista_vacia

nuevo_ensayo <-- e // el valor asignado a la posicion K es true

nuevo_ensayo.suma <-- e.suma + datos[k]

nuevo_ensayo.num_sumados <-- e.num_sumados + 1

lista_compleciones <-- anadir(lista_compleciones, nuevo_ensayo)

nuevo_ensayo <-- e // el valor asignado a la posicion K es false

nuevo_ensayo.candidatos[k] <-- false

lista_compleciones <-- anadir(lista_compleciones, nuevo_ensayo)

dev lista_compleciones

funcion esprometedora(e:ensayo) dev booleano

si (e.num_sumados < m) entonces

dev cierto

si no

dev falso

funcion valido(e:ensayo) dev booleano

si (e.suma = C) y (e.num_sumados = m) entonces

dev cierto

si no

dev falso

4. Complejidad del algoritmo En cada nivel el arbol se divide como maximoen dos ramas (si no se ha llegado a tener m posicione a true). Luego una cotasuperior es 2n.

Page 266: Examenes resueltos

Podemos observar que

si m → n =⇒ T (n) ∈ O(2n)si m → 1 =⇒ T (n) ∈ O(n)

Este algoritmo serıa mas eficiente que el anterior cuando m → n.

Page 267: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2007 – Original Cuestión 1 (1 punto). Describe el grafo asociado al espacio de soluciones del problema del n-puzzle (Práctica de este curso). Cuestión 2 (2,5 puntos). Supongamos que un polinomio se representa por un vector v[0..n] de longitud n+1 donde el valor v[i] es el coeficiente de grado i. Describir claramente los cálculos y la descomposición algorítmica necesaria para plantear un algoritmo, de orden mejor que cuadrático, que multiplique dos polinomios P(x) y Q(x) mediante divide y vencerás. NOTA: La solución típica trivial de orden cuadrático puntúa 0 puntos. Cuestión 3 (2,5 puntos). Con respecto al algoritmo de ordenación por fusión (Mergesort).

1. Escribe el algoritmo. 2. Dibuja la secuencia de llamadas del algoritmo y la evolución del siguiente vector al ordenarlo.

Para ello ten en cuenta que hay que considerar que el problema es suficientemente pequeño cuando el subarray es de tamaño 2.

(2,0,2,1,9,6,2,3,5,8)

Problema (4 puntos). Tenemos n objetos de volúmenes v1... vn, y un número ilimitado de recipientes iguales con capacidad R (con ,iv R i≤ ∀ ). Los objetos se deben meter en los recipientes sin partirlos, y sin superar su capacidad máxima. Se busca el mínimo número de recipientes necesarios para colocar todos los objetos. La resolución de este problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico más apropiado para resolver el problema. Escriba dicho esquema general.(0,5 puntos). 2. Descripción de las estructuras de datos necesarias (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2 puntos). 4. Estudio del coste del algoritmo desarrollado (1 punto).

Page 268: Examenes resueltos
Page 269: Examenes resueltos

procedimiento ordenarporfusión (T[1..n])si n es suficientemente pequeño entonces insertar(T)sino

matriz U[1..1 + n/2 ], V[1..1 + n/2 ],

U[1.. n/2 ] T[1.. n/2⎢ ⎥ ⎢ ⎥⎣ ⎦ ⎣ ⎦

←⎢ ⎥ ⎢ ⎥⎣ ⎦ ⎣ ⎦

]

V[1.. n/2 ] T[1 + n/2 ..n]

ordenarporfusión(U[1.. n/2 ] )

ordenarporfusión(V[1.. n/2 ] )fusionar(U,V,T)

fsifprocedimiento

←⎡ ⎤ ⎢ ⎥⎢ ⎥ ⎣ ⎦⎢ ⎥⎣ ⎦⎡ ⎤⎢ ⎥

procedimiento fusionar(U[1..m+1], V[1..n+1], T[1..m+n])Fusionar las matrices ordenadas U[1..m] y V[1..n] almacenándolas enT[1..m+n],U[m+1] y V[n+1] se utilizan como centinelasi, j 1U[m+1], V[n+1]

←←

para k 1 hasta m+n hacersi U[i] < V[j]entonces T[k] U[i];i i + 1sino T[k] V[j]; j j + 1fsi

fparafprocedimiento

∞←

← ←← ←

RESPUESTAS EXAMEN Programación III. Septiembre 2007 (Original) Cuestión 1 (1 punto). Describe el grafo asociado al espacio de soluciones del problema del n-puzzle (Práctica de este curso). Solución: • Cada nodo se bifurca como máximo en los cuatro movimientos posibles del hueco (arriba, abajo,

Izquierda, y derecha), siempre que sea posible. • La profundidad del árbol está limitada por el número de distintos tableros posibles ((nxn)!, siendo n el

tamaño del lado del tablero), ya que no se deben repetir. Cuestión 2 (2,5 puntos). Supongamos que un polinomio se representa por un vector v[0..n] de longitud n+1 donde el valor v[i] es el coeficiente de grado i. Describir claramente los cálculos y la descomposición algorítmica necesaria para plantear un algoritmo, de orden mejor que cuadrático, que multiplique dos polinomios P(x) y Q(x) mediante divide y vencerás. NOTA: La solución típica trivial de orden cuadrático puntúa 0 puntos. Solución: Es relativamente simple dar con la solución de orden cuadrático. En este caso, se descompone en mitades P(x) = Axn/2+B y Q(x) = Cxn/2 +D con A,B,C,D polinomios de grado n/2 sacando factor común xn/2 como se detalla en las expresiones. De esta forma se ve claramente que P·Q es (Axn/2 +B)·( Cxn/2+D) = AC xn + (AD+BC)xn/2 + BD lo que la solución conlleva 4 multiplicaciones de grado n/2. El coste sería en este caso cuadrático. Sin embargo hay una manera de organizar las operaciones mediante la cual, no es necesario calcular AD+BC mediante 2 productos, sino sólo con uno, aprovechando que ya tenemos realizados los productos BD y AC. En este último caso basta con observar que (A+B)·( C+D) = AC+BC+AD+BD y que BC+AD = (A+B)·( C+D) – AC – BD con lo que es posible realizar el cálculo con 3 productos en lugar de 4, ya que el coste de las sumas, si consideramos las multiplicaciones como lineales, sería constante. De manera que (A+B)·( C+D) sería uno de los productos, y AC y BD los otros dos. Este problema es similar al problema de la multiplicación de números enteros muy grandes del texto base, capítulo 7. Cuestión 3 (2,5 puntos). Con respecto al algoritmo de ordenación por fusión (Mergesort). a) Escribe el algoritmo. (a) El algoritmo se puede encontrar en Brassard & Bratley, pag. 258 b) Dibuja la secuencia de llamadas del algoritmo y la evolución del siguiente vector al ordenarlo. Para ello ten en cuenta que hay que considerar que el problema es suficientemente pequeño cuando el subarray es de tamaño 2. (2,0,2,1,9,6,2,3,5,8)

Page 270: Examenes resueltos

(b) OrdFusion(2,0,2,1,9,6,2,3,5,8)

OrdFusion(2,0,2,1,9) OrdFusion(2,0)

Insertar(2,0) -> (0,2) OrdFusion(2,1,9)

OrdFusion(2) Insertar(2) -> (2)

OrdFusion(1,9) Insertar(1,9) -> (1,9)

Fusionar((2),(1,9)) -> (1,2,9) Fusionar((0,2),(1,2,9)) -> (0,1,2,2,9)

OrdFusion(6,2,3,5,8) OrdFusion(6,2)

Insertar(6,2) -> (2,6) OrdFusion(3,5,8)

OrdFusion(3) Insertar(3) -> (3)

OrdFusion(5,8) Insertar(5,8) -> (5,8)

Fusionar((3),(5,8)) -> (3,5,8) Fusionar((2,6),(3,5,8)) -> (2,3,5,6,8)

Fusionar((0,1,2,2,9), (2,3,5,6,8)) -> (0,1,2,2,2,3,5,6,8,9) Problema (4 puntos). Tenemos n objetos de volúmenes v1... vn, y un número ilimitado de recipientes iguales con capacidad R (con ,iv R i≤ ∀ ). Los objetos se deben meter en los recipientes sin partirlos, y sin superar su capacidad máxima. Se busca el mínimo número de recipientes necesarios para colocar todos los objetos. La resolución de este problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico más apropiado para resolver el problema. Escriba dicho esquema general.(0,5 puntos). 2. Descripción de las estructuras de datos necesarias (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2 puntos). 4. Estudio del coste del algoritmo desarrollado (1 punto). Solución: Resuelto en Estructuras de datos y métodos algorítmicos. N.Martí, Y. Ortega, J.A Verdejo. Pearson education, 2004. Ejercicio 15.9. Indicaciones: 1. Ramificación y poda. Se trata de un problema de optimización, para el que no existe una función de selección que permita ir seleccionando a cada paso el objeto que de lugar a la construcción parcial de la solución óptima. Por tanto no es posible aplicar un algoritmo voraz. Tampoco existe una forma de dividir el problema en subproblemas que se puedan resolver independientemente, por lo que tampoco es posible un esquema divide y vencerás. 2. vector de objetos: Podemos representar el reparto de objetos entre recipientes mediante un vector en el que cada posición indique a qué recipiente se ha asignado el objeto correspondiente.

Page 271: Examenes resueltos

objetos = vector[1..n] of entero La solución es la cantidad entera S de recipientes empleados. Montículo de mínimos en el que cada componente almacene una solución parcial (nodo) con su cota correspondiente. 4. El número de recipientes está limitado a n, es decir al número de objetos. Una estimación del coste es el tamaño del árbol, que en el peor caso crece como ( )!nΟ , ya que cada nodo del nivel k puede expandirse con los n-k objetos que quedan por asignar a recipientes. Solución: En la solución del ejercicio 14.22, página 499 de Estructura de datos y métodos algorítmicos, se supone que todo objeto cabe en un envase vacío y, por tanto, se necesitan un máximo de n envases. Las soluciones se representan en tuplas de la forma (x1,…,xn) donde xi es el envase donde hemos colocado el objeto i. Como los envases son indistinguibles, el primer objeto siempre se coloca en el primer envase (x1 = 1) y para cada objeto de los restantes se puede usar uno de los envases ya ocupados, si cabe en alguno, o coger uno vacío. En cuanto a las estimaciones a utilizar para el esquema optimista-pesimista, tenemos: Optimista: una cota inferior adecuada es el número de envases ya utilizados en la solución parcial. Pesimista: una cota superior muy sencilla es considerar un envase extra por cada objeto que nos queda por empaquetar, pero resulta demasiado grosera. Podemos en cambio ir considerando cada objeto restante, en el orden que se haya dado, e intentar meterlo en el primer envase utilizand y, en el caso en que no quepa, intentarlo con el segundo envase, y así hasta agotar todas las posibilidades, en cuyo caso, se añadirá un nuevo envase a la solución parcial. En cada nodo, además de la información usual (solución parcial, etapa y prioridad), guardamos el número de envases utilizados y las capacidades disponibles de cada envase utilizado.

Además, como en la solución mediante la técnica de vuelta atrás (véase el ejercicio 14.22), la búsqueda podrá acabarse si encontramos una solución con el valor

1

nii

voptimo

E=

⎡ ⎤⎢ ⎥=⎢ ⎥⎢ ⎥

tipos nodo = reg sol[1..n]de 1..n k:1..n envases:1..n prioridad capacidad[1..n]de real freg ftipos

Page 272: Examenes resueltos

El algoritmo es el siguiente:

Para calcular las estimaciones

fun empaquetar-rp(E:real,V[1..n]de real)dev (sol-mejor[1..n]de 1..n, envase-mejor:1..n) var X,Y: nodo,C:colapr[nodo] total:=0 para i = 1 hasta n hacer total := total +V[i] fpara optimo:= /total E⎡ ⎤⎢ ⎥

encontrada:=falso generamos raíz: el primer objeto en el primer envase Y.k:=1; Y.sol[1]:=1; Y.envases:=1 Y.capacidad[1]:= E - V[1]; Y.capacidad[2..n]:= V[E] C:= cp-vacia(); añadir(C,Y) envases-mejor:=calculo-pesimista(E,V,Y) mientras ¬encontrada ^ ¬es-cp-vacia?(C)^(minimo(C).envases ≤ envases-mejor) hacer Y:=minimo(C); eliminar-min(C) generamos los hijos de Y X.k:=Y.k+1; X.sol:=Y.sol X.envases:= Y.envases; X.capacidad:= Y.capacidad; probamos con cada envase ya utilizado i:=1 mientras i ≤ Y.envases ^ ¬encontrada hacer si X.capacidad[i] ≥ V[X.k] entonces X.sol[X.k]:=i; X.capacidad[i]:= X.capacidad[i]- V[X.k] si X.k = n entonces sol-mejor:=X.sol; envase-mejor:= X.envases encontrada:= (envases-mejor = optimo) terminar sino añadir(C,X) pes:=calculo-pesimista(E,V,X) envases-mejor:=min(envases-mejor, pes) fsi X.capacidad[i]:= Y.capacidad[i] fsi fpara si ¬encontrada entonces probamos con un nuevo envase nuevo:= Y.envases + 1 X.sol[X.k]:=nuevo; X.envases:= nuevo X.capacidad[nuevo]:= E - V[X.k] si X.envases ≤ envases-mejor entonces si X.k = n entonces sol-mejor:=X.sol; envases-mejor:= nuevo encontrada:= (envases-mejor = optimo) terminar sino añadir(C,X) pes:= calculo-pesimista(E,V,X) envases-mejor:= min(envases-mejor,pes) fsi fsi fmientras ffun

fun calculo-pesimista (E:real,V[1..n]de real,X:nodo)dev pes:1..nvar capacidad-aux[1..n]de real pes:=X.envases; capacidad-aux:= X.capacidad para i = X.k+1 hasta n hacer j:= 1 mientras V[i] > capacidad-aux [j] hacer j:= j+1 fmientras capacidad-aux [j] := capacidad-aux [j] - V[i] pes := pes(pes,j) fpara ffun

Page 273: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2007 Reserva Cuestión 1 (2 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

Cuestión 2 (2 puntos). Dos amigos juegan a un sencillo juego de adivinación: uno de ellos piensa un número natural positivo y el otro debe adivinarlo preguntando solamente si es menor o igual que otros números. ¿Qué esquema algorítmico utilizaría para adivinar el número en tiempo logarítmico? Diseñe el algoritmo y escríbalo en pseudocódigo. (Resuelto en Estructuras de datos y métodos algorítmicos pag 312) Cuestión 3 (2 puntos). Declarar en Java las clases y/o estructuras de datos que utilizaría en el problema de puzzle (práctica de este año). Problema (4 puntos). La agencia matrimonial Celestina & Co. Quiere informatizar parte de la organización de parejas entre sus clientes. Cuando un cliente llega a la agencia se describe a sí mismo y cómo le gustaría que fuera su pareja. Con la información de los clientes la agencia construye dos matrices M y H que contienen las preferencias de los unos por los otros, tales que la fila M[i,·] es una ordenación de mayor a menor de las mujeres según las preferencias del i-ésimo hombre y la fila H[i,·] es una ordenación de mayor a menor de los hombres según las preferencias de la i-ésima mujer. Por ejemplo, M[i,1] almacenaría a la mujer preferida por el hombre i y M[i,2] a su segunda preferida. Dado el alto índice de divorcios, la empresa se ha planteado como objetivo que los emparejamientos sean lo más estables posible evitando las siguientes situaciones: 1) Que dada una pareja (h’,m’) se de el caso de m’ prefiera un h sobre h’ y además h’ prefiera a un m sobre m’. 2) Que dada una pareja (h”,m”) se de el caso de h” prefiera un m sobre m” y además m prefiera a h sobre h”. La agencia quiere que dadas las matrices de preferencia, un programa establezca parejas evitando las dos situaciones descritas con anterioridad. La resolución de este problema debe incluir, por este orden: 1. Elección del esquema más apropiado, el esquema general y explicación de aplicación al problema. (1 punto). 2. Descripción de las Estructuras de datos necesarias. (0,5 puntos) 3. Algoritmo completo a partir del refinamiento del esquema general. (2 puntos) 4. Estudio del coste del algoritmo desarrollado. (0,5 puntos)

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 2, k-1); r ← r + uno (n DIV 2, k+1); r ← r + uno (n DIV 2, k+2); DEVOLVER (1); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 2, k-1); r ← r + dos (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 274: Examenes resueltos
Page 275: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2007 (Reserva) Cuestión 1 (2 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

El procedimiento uno tiene: Una instrucción constante, que no tenemos en cuenta para el cálculo, o bien tres llamadas recursivas, ambas invocan la función con un tamaño n/2. //En el segundo y tercer caso de la llamada recursiva hay otra instrucción simple añadida. La expresión queda T(n) = T(n/2) + T(n/2) + T(n/2) lo que equivale a T(n) = 3T(n/2) + c. Aplicando la resolución genérica de las expresiones del tipo: T(n) = aT(n/b)+cnk

con k = 0, a=3 y b=2 queda que 3 > 20 y por tanto la función T(n) tiene un coste ( )2log 3nΘ

El procedimiento dos tiene: Una llamada recursiva de tamaño n/2, Otra llama recursiva de tamaño n/2, Un bucle en el que se repite n veces un cálculo consistente en llamar dos veces a una función h(n;r;k) de coste lineal, /*más una instrucción simple*/, y por último Una instrucción simple /* que no tenemos en cuenta para el calculo*/ y otra llamada recursiva de tamaño n/2. Sumando los términos nos sale T(n) = T(n/2) +T(n/2)+n (2n) +T(n/2), lo que equivale a T(n) = 3T(n/2) + 2n2 Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk y siendo 3 < 2 2 el coste es Θ(n2). a = 3, b = 2, k = 2

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 2, k-1); r ← r + uno (n DIV 2, k+1); r ← r + uno (n DIV 2, k+2); DEVOLVER (1); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 2, k-1); r ← r + dos (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 276: Examenes resueltos

Cuestión 2 (2 puntos). Dos amigos juegan a un sencillo juego de adivinación: uno de ellos piensa un número natural positivo y el otro debe adivinarlo preguntando solamente si es menor o igual que otros números. ¿Qué esquema algorítmico utilizaría para adivinar el número en tiempo logarítmico? Diseñe el algoritmo y escríbalo en pseudocódigo. (Resuelto en Estructuras de datos y métodos algorítmicos pag 312) Solución: Como el número a adivinar puede ser arbitrariamente grande, empezar por el 1 y seguir después en secuencia hasta alcanzar el número propuesto no es un método práctico. En su lugar, necesitamos hacer una búsqueda binaria, que nos permita reducir de forma más rápida el conjunto de candidatos. Sin embargo, el algoritmo de búsqueda binaria funciona con vectores de tamaño fijo y conocido, por lo que lo primero será encontrar alguna cota superior del número a adivinar, en principio una cota inferior es 1. Para encontrar dicha cota habrá que seguir un método que genere números cada vez más grandes y de modo que el incremento también aumente de forma rápida. A tal efecto, podemos utilizar, por ejemplo, las potencias de 2. Para adivinar el número utilizaremos una variación de la búsqueda binaria donde no necesitamos un vector porque se trabaja con un intervalo de enteros positivos y además siempre vamos a tener éxito. Esta nueva versión en lugar de recibir el número a buscar como argumento lo devuelve como resultado, para ello utiliza una función interna menor-igual que devuelve cierto si y solo si el número a adivinar es menor o igual que el propuesto como argumento. fun bus-bin2 (c,f) dev n:nat si c = f entonces dev c sino m = (c+f)div 2 si menor-igual (m) entonces dev bus-bin2(c,m) sino dev bus-bin2(m+1,f) fsi fsi ffun fun adivinar() dev n:nat encontrar cotas superior e inferior cinf = 1; csup = 1; mientras ¬ menor-igual(csup) hacer cinf = csup+1; csup = 2*csup; fmientras n = bus-bin2 (cinf,csup) ffun Aunque la función no recibe argumento alguno, su resultado depende del número oculto a adivinar, el cual determina el comportamiento de la función menor-igual. Si n es el número a adivinar, para determinar el intervalo donde hacer la búsqueda binaria se necesitan ⎡ ⎤ 1log += nm preguntas y el tamaño del intervalo donde hacer la búsqueda binaria es 2m . Por tanto la cantidad total de preguntas a realizar, en el caso peor está en )(lognΘ . Podríamos considerar otra base para las potencias, observando que cuanto mayor sea dicha base antes se encontrará la cota superior. Sin embargo hay que tener en cuenta que en general el intervalo que quedará para la búsqueda binaria será también mayor. Cuestión 3 (2 puntos). Declarar en Java las clases y/o estructuras de datos que utilizaría en el problema de puzzle (práctica de este año).

Page 277: Examenes resueltos

Problema (4 puntos). La agencia matrimonial Celestina & Co. Quiere informatizar parte de la organización de parejas entre sus clientes. Cuando un cliente llega a la agencia se describe a sí mismo y cómo le gustaría que fuera su pareja. Con la información de los clientes la agencia construye dos matrices M y H que contienen las preferencias de los unos por los otros, tales que la fila M[i,·] es una ordenación de mayor a menor de las mujeres según las preferencias del i-ésimo hombre y la fila H[i,·] es una ordenación de mayor a menor de los hombres según las preferencias de la i-ésima mujer. Por ejemplo, M[i,1] almacenaría a la mujer preferida por el hombre i y M[i,2] a su segunda preferida. Dado el alto índice de divorcios, la empresa se ha planteado como objetivo que los emparejamientos sean lo más estables posible evitando las siguientes situaciones: 1) Que dada una pareja (h’,m’) se de el caso de m’ prefiera un h sobre h’ y además h’ prefiera a un m sobre m’. 2) Que dada una pareja (h”,m”) se de el caso de h” prefiera un m sobre m” y además m prefiera a h sobre h”. La agencia quiere que dadas las matrices de preferencia, un programa establezca parejas evitando las dos situaciones descritas con anterioridad. La resolución de este problema debe incluir, por este orden: 1. Elección del esquema más apropiado, el esquema general y explicación de aplicación al problema. (1 punto). 2. Descripción de las Estructuras de datos necesarias. (0,5 puntos) 3. Algoritmo completo a partir del refinamiento del esquema general. (2 puntos) 4. Estudio del coste del algoritmo desarrollado. (0,5 puntos) 1. Elección del esquema:

fun vuelta - atrás(ensayo)si valido (ensayo) es una solución entonces dev ensayosi no para cada hijo compleciones (ensayo) hacer

si condiciones de poda (hijo) hacer vuelta - at∈

rás(hijo) fsifpara

fsiffun

2. Descripción de las Estructuras de datos necesarias • Dos matrices m[1..n, 1..n ] y h[1..n, 1..n ] que contienen las preferencias de unos por los otros.

m [i,j] : mujer a la que prefiere el hombre i-ésimo en el lugar de preferencia j-ésimo. h [i,j] : hombre al que prefiere la mujer i-ésima en el lugar de preferencia j-ésimo.

• Un array asignado[1..n] que indicará si una mujer está o no asignada libre [i] : valor booleano que indica si la mujer i-ésima ha sido asignada.

Comportamiento del algoritmo: • El algoritmo trabajará por etapas y en cada etapa k decide la mujer que ha de emparejarse con el hombre k-ésimo • En una etapa cualquiera k, el k-ésimo hombre escogerá la mujer que prefiere en primer lugar siempre que ésta esté libre y la pareja resulte estable

Page 278: Examenes resueltos

3. Algoritmo completo a partir del refinamiento del esquema general.o

4. Estudio del coste del algoritmo desarrollado.

Sea T(n) el tiempo de ejecución del algoritmo.

El algoritmo principal posee un bucle para que se ejecuta n veces y llamada recursiva que se ejecuta también n veces.

El coste adicional sale de que esta función llama a la función estable, esta función posee una complejidad O(n4).

Si sumamos ambas complejidades obtenemos: 4O(n!) + O(n ) = O(n!)

Se deduce que la complejidad temporal es: O(T(n))= O(n!)

proc parejasVA (H[1..n,1..n],M[1..n,1..n],sol[1..n]1..n,k:1..n,asignado[1..n]bool) para hombre = 1 hasta n hacer si ¬asignado[hombre] entonces sol[k] = hombre asignado[hombre] = cierto si estable?(H,M,sol,k) entonces si k = n entonces imprimir (sol) sino parejasVA(H,M,sol,k+1,asignado) fsi fsi asignado[hombre] = falso fsi fpara fproc

fun estable?(H[1..n,1..n],M[1..n,1..n],sol[1..n]1..n,k:1..n) dev respuesta bool respuesta = cierto; i=1; mientras i<k ∧ respuesta hacer respuesta = (M[k, sol[i]] ≤ M[k, sol[k]] ∨ H[sol[i], k] ≤ H[sol[i], i]) ∧ (M[i, sol[k]] ≤ M[i, sol[i]] ∨ H[sol[k], i] ≤ H[sol[k], k]) i= i+1; fmientras ffun

proc parejas (H[1..n,1..n],M[1..n,1..n]) var sol[1..n], asignado[1..n]bool asignado[1..n] = [falso]; parejasVA (H, M, sol, 1, asignado) fproc

Page 279: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2008 – Primera semana Cuestión 1 (1,5 puntos). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 1 1 2 2 2 1 X X X

1 X 3

1 1 Cuestión 2 (2 puntos). ¿Cuáles de las siguientes afirmaciones son verdaderas y cuales falsas? Demuestra tus respuestas. a) 2 3n O(n )∈ ; b) 2 3n (n )∈Ω ; c) 24 3 2 ( log )n n n n− + ∈Ω ; d) ! (2 1)n n∈Θ + Cuestión 3 (2,5 puntos). En una fontanería se necesitan hacer n reparaciones urgentes, y sabe de antemano el tiempo que le va a llevar cada una de ellas: en la tarea i-ésima tardará ti minutos. Como en su empresa le pagan dependiendo de la satisfacción del cliente, necesita decidir el orden en el que atenderá los avisos para minimizar el tiempo medio de espera de los clientes. Si llamamos Ei a lo que espera el cliente i-ésimo hasta ver reparada su avería por completo, necesita minimizar la expresión:

1( )

n

ii

E n E=

= ∑

Indica qué esquema o esquemas consideras más adecuados para resolver este problema en los siguientes casos:

• La empresa sólo dispone de un fontanero para realizar las reparaciones y quiere minimizar el tiempo medio de espera de los clientes.

• La empresa dispone de F fontaneros para realizar las reparaciones y quiere minimizar el tiempo medio de espera de los clientes.

Además de nombrar el esquema o esquemas, explica el porque de su elección, los aspectos destacados de cómo resolverías el problema (función de selección, restricciones, cotas en función del esquema propuesto) y el coste asociado. No se piden los algoritmos. Problema (4 puntos). El tío Facundo posee n huertas, cada una con un tipo diferente de árboles frutales. Las frutas ya han madurado y es hora de recolectarlas. El tío Facundo conoce, para cada una de las huertas, el beneficio bi que obtendría por la venta de lo recolectado. El tiempo que se tarda en recolectar los frutos de cada finca es así mismo variable (no unitario) y viene dado por ti. También sabe los días di que tardan en pudrirse los frutos de cada huerta. Se pide ayudar a decidir al tío Facundo que debe recolectar para maximizar el beneficio total obtenido. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2 puntos). 4. Estudio del coste (1 punto).

Page 280: Examenes resueltos
Page 281: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2008 (Primera Semana) Cuestión 1 (1,5 puntos). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 1 1 2 2 2 1 X X X 1 X 3 1 1

1 1 1 1 1 2 2 2 1 X X X 1 X 3 X X X 1 1 X X

Fila 3 Fila 4

X O

X X X O O X O O

X X X X X O O X X O X O

O X X X O X X O

X

X X X O

O

X O X X O O

X O O X X O O O

Page 282: Examenes resueltos

Cuestión 2 (2 puntos). ¿Cuáles de las siguientes afirmaciones son verdaderas y cuales falsas? Demuestra tus respuestas. a) 2 3n O(n )∈ ; b) 2 3n (n )∈Ω ; c) 24 3 2 ( log )n n n n− + ∈Ω ; d) ! (2 1!)n n∈Θ + REGLA DEL LÍMITE:

1. Si ( )( )n

f nlim

g n+

→∞∈ℜ , entonces ( ) ( )( )f n g n∈Θ

2. Si ( )( )

0n

f nlim

g n→∞∈ , entonces ( ) ( )( )f n O g n∈ pero ( ) ( )( )f n g n∉Θ

3. Si ( )( )n

f nlim

g n→∞∈ +∞ , entonces ( ) ( )( )f n g n∈Ω pero ( ) ( )( )f n g n∉Θ

a) 2 3n O(n )∈

2

3 2

2 2 0lim lim lim 03 6 6n n n

n nn n n→∞ →∞ →∞

= = = =

Por lo tanto a es cierto. b) 2 3n (n )∈Ω

2

3 2

2 2 0lim lim lim 03 6 6n n n

n nn n n→∞ →∞ →∞

= = = =

Por lo tanto b es falso. c) 24 3 2 ( log )n n n n− + ∈Ω

2

1

4 3 2 8 3 8lim limlog ln 1n n

n

n n nn n n→∞ →∞

− + −= = = +∞

+

Por lo tanto c es cierto. d) ! (2 1!)n n∈Θ +

[ ]( 1)! /! ( 1)! ( 1)!lim lim lim lim2 1! 2 1 2 / 1/ 2n n n n

n n nn n n nn n n n n→∞ →∞ →∞ →∞

⋅ −⋅ − −= = = = +∞

+ + +

Por lo tanto d es falso. Cuestión 3 (2,5 puntos). En una fontanería se necesitan hacer n reparaciones urgentes, y sabe de antemano el tiempo que le va a llevar cada una de ellas: en la tarea i-ésima tardará ti minutos. Como en su empresa le pagan dependiendo de la satisfacción del cliente, necesita decidir el orden en el que atenderá los avisos para minimizar el tiempo medio de espera de los clientes. Si llamamos Ei a lo que espera el cliente i-ésimo hasta ver reparada su avería por completo, necesita minimizar la expresión:

1( )

n

ii

E n E=

= ∑

Page 283: Examenes resueltos

Indica qué esquema o esquemas consideras más adecuados para resolver este problema en los siguientes casos:

• La empresa sólo dispone de un fontanero para realizar las reparaciones y quiere minimizar el tiempo medio de espera de los clientes.

• La empresa dispone de F fontaneros para realizar las reparaciones y quiere minimizar el tiempo medio de espera de los clientes.

Además de nombrar el esquema o esquemas, explica el porque de su elección, los aspectos destacados de cómo resolverías el problema (función de selección, restricciones, cotas en función del esquema propuesto) y el coste asociado. No se piden los algoritmos. Solución: Técnicas De Diseño De Algoritmos, Universidad de Málaga 166 y 167. En primer lugar hemos de observar que el fontanero siempre tardará el mismo tiempo global T = t1 + t2 + ... + tn

en realizar todas las reparaciones, independientemente de la forma en que las ordene. Sin embargo, los tiempos de espera de los clientes sí dependen de esta ordenación. En efecto, si mantiene la ordenación original de las tareas (1, 2, ..., n), la expresión de los tiempos de espera de los clientes viene dada por: E1 = t1

E2 = t1 + t2

..... En = t1 + t2 + ... + tn . Lo que queremos encontrar es una permutación de las tareas en donde se minimice la expresión de E(n) que, basándonos en las ecuaciones anteriores, viene dada por: Vamos a demostrar que la permutación óptima es aquella en la que los avisos se atienden en orden creciente de sus tiempos de reparación. Para ello, denominemos X = (x1,x2,...,xn) a una permutación de los elementos (1,2,...,n), y sean (s1,s2,...,sn) sus respectivos tiempos de ejecución, es decir, (s1,s2,...,sn) va a ser una permutación de los tiempos orginales (t1,t2,...,tn). Supongamos que no está ordenada en orden creciente de tiempo de reparación, es decir, que existen dos números xi < xj tales que si > sj. Sea Y = (y1,y2,...,yn) la permutación obtenida a partir de X intercambiando xi con xj, es decir, yk = xk si k ≠ i y k ≠ j, yi = xj, yj = xi. Si probamos que E(Y) < E(X) habremos demostrado lo que buscamos, pues mientras más ordenada (según el criterio dado) esté la permutación, menor tiempo de espera supone. Pero para ello, basta darse cuenta que

( ) ( ) ( ) ( ),

n

i j j i kk=1 k i,k j

E Y = n - x +1 s + n - x +1 s + n - k +1 s≠ ≠

y que, por tanto:

( ) ( ) ( )( ) ( )( ) ( )( ) 0i i j j j i j i i jE X E Y = n - x +1 s s n - x +1 s s x x s s− − + − = − − >

En consecuencia, el algoritmo pedido consiste en atender a las llamadas en orden inverso a su tiempo de reparación. Con esto conseguirá minimizar el tiempo medio de espera de los clientes, tal y como hemos probado. En el segundo caso también tenemos que minimizar el tiempo medio de espera de los clientes, pero lo que ocurre es que ahora existen F fontaneros dando servicio simultámeamente. Basándonos en el método utilizado anteriormente, la forma óptima de atender los avisos va a ser la siguiente:

• En primer lugar, se ordenan los avisos por orden creciente de tiempo de reparación. • Un vez hecho esto, se van asignando los avisos por este orden, siempre al fontanero menos ocupado. En

caso de haber varios con el mismo grado de ocupación, se escoge el de número menor. En otras palabras, si los avisos están ordenados de forma que ti ≤ tj si i < j, asignaremos al fontanero k los avisos k, k+F, k+2F, ...

Page 284: Examenes resueltos

Problema (4 puntos). El tío Facundo posee n huertas, cada una con un tipo diferente de árboles frutales. Las frutas ya han madurado y es hora de recolectarlas. El tío Facundo conoce, para cada una de las huertas, el beneficio bi que obtendría por la venta de lo recolectado. El tiempo que se tarda en recolectar los frutos de cada finca es así mismo variable (no unitario) y viene dado por ti. También sabe los días di que tardan en pudrirse los frutos de cada huerta. Se pide ayudar a decidir al tío Facundo que debe recolectar para maximizar el beneficio total obtenido. (Solucionado en el ejercicio 15.4 pág 516 de Estructura de datos y métodos algorítmicos) Solución: En el ejercicio 14.6, página 463 de Estructura de datos y métodos algorítmicos, vimos la solución a este problema mediante la técnica de vuelta atrás. Representamos las soluciones mediante tuplas (x1,…,xn) donde xi = 1 indica que los frutos de la huerta i se recolectan mientras que xi = 0 indica que los frutos de la huerta no se recolectan. También vimos como comprobar que un subconjunto de huertas es factible, es decir, que todas pueden recolectarse sin superar su plazo, manteniendo las huertas ordenadas por tiempo de caducidad creciente. En cuanto a las estimaciones a utilizar para el esquema optimista-pesimista, tenemos: Optimista: Como ya vimos en el ejercicio 14.6, podemos aproximar superiormente el beneficio obtenible sumando el beneficio de todas las huertas que pueden recolectarse sin llegar a su fecha de caducidad después de las ya elegidas (es decir, empezando a recolectar cada una justo después de terminar con la última finca ya elegida). Pesimista: igual que en el ejercicio 15.2, podemos obtener una cota pesimista calculando una posible solución extensión de la que tengamos: las huertas no consideradas se van recolectando en orden (acumulando el tiempo), siempre que no se supere su fecha de caducidad. En cada nodo, además de la información usual (solución parcial, etapa y prioridad), mantendremos el tiempo y beneficio acumulados.

tipos nodo = reg sol[1..n]de 0..1 k:0..n tiempo.beneficio:real beneficio-opt:real prioridad freg ftipos

fun calculo-pesimista (T[1..n],B[1..n],B[1..n]de real,k:0..n,tiempo,beneficio:real)dev pes:real pes:=beneficio; tiempo-pes:= tiempo para i = k+1 hasta n hacer si tiempo-pes+T[i] ≤ D [i] entonces pes := pes+ B[i]; tiempo-pes:= tiempo-pes+T[i] fsi fpara ffun

fun calculo-optimista (T[1..n],B[1..n],B[1..n]de real,k:0..n,tiempo,beneficio:real)dev opt:real opt:=beneficio para i = k+1 hasta n hacer si tiempo+T[i] ≤ D [i] entonces opt := opt+ B[i] fsi fpara ffun

Page 285: Examenes resueltos

El algoritmo es el siguiente: Las funciones que calculan las estimaciones son las siguientes:

fun huertas-rp(T[1..n],D[1..n],B[1..n]de real)dev (sol-mejor[1..n]de 0..1, beneficio-mejor:real)var X,Y: nodo,C:colapr[nodo] generamos raíz Y.k:=0; Y.tiempo:=0; Y.beneficio:=0 Y.beneficio-opt:=calculo-optimista(T,D,B,Y.k,Y.tiempo,Y.beneficio) C:= cp-vacia(); añadir(C,Y) beneficio-mejor:=calculo-pesimista(T,D,B,Y.k,Y.tiempo,Y.beneficio) mientras ¬es-cp-vacia?(C)^(maximo(C).beneficio-opt ≥ beneficio-mejor) hacer Y:=maximo(C); eliminar-max(C) X.k:=Y.k+1; X.sol:=Y.sol hijo izquierdo - recolectar si Y.tiempo+T[X.k] ≤ D[X.k] entonces es factible X.sol[X.k]:=1; X.tiempo:= Y.tiempo+T[X.k] X.beneficio:= Y.beneficio + B[X.k] X.beneficio-opt:= calculo-optimista(T,D,B,X.k,X.tiempo,X.beneficio) si X.beneficio-opt ≥ beneficio-mejor entonces si X.k = n entonces sol-mejor:=X.sol; beneficio-mejor:= X.beneficio sino añadir(C,X) la estimación pesimista coincide con la de Y beneficio-mejor no cambia fsi fsi fsi hijo deerecho – no recolectar X.sol[X.k]:=0; X.tiempo:= Y.tiempo X.beneficio:= Y.beneficio X.beneficio-opt:= calculo-optimista(T,D,B,X.k,X.tiempo,X.beneficio) si X.beneficio-opt ≥ beneficio-mejor entonces si X.k = n entonces sol-mejor:=X.sol; beneficio-mejor:= X.beneficio sino añadir(C,X) pes:= calculo-pesimista(T,D,B,X.k,X.tiempo,X.beneficio) beneficio-mejor:= max(beneficio-mejor,pes) fsi fsi fmientras ffun

Page 286: Examenes resueltos
Page 287: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2008 – Segunda semana Cuestión 1 (2 puntos). En la práctica obligatoria del presente curso 2007/2008 se ha tenido que diseñar y desarrollar un algoritmo para resolver el problema del nonograma. Dado el cuadrado de 4x4 de la figura, trazar el algoritmo que lo resuelve tal como lo hace el desarrollado para la práctica y explicar cada paso. Hacer al menos 3 niveles y al menos 2 backtrakings. Restricciones del nonograma:

1 1 1 1 1 2 2 2 1 X X X

1 X 3 X X X

1 1 X X

Cuestión 2 (2 puntos). Sea T[1..n] con k elementos (k<n) un montículo de mínimos. Se pide programar una función “flotar” recursiva que dado un nuevo elemento T[k+1] restaure la propiedad de montículo en T. Una función iterativa que lo resuelva puntuará cero puntos. Cuestión 3 (2 puntos). Dado n potencia de 2, escribe un algoritmo recursivo que calcule en tiempo logarítmico el valor de an suponiendo que solo se pueden realizar multiplicaciones y que éstas tienen coste unitario. Demuestre el coste mediante la ecuación de recurrencia. No justifique el esquema usado, aplíquelo. Problema (4 puntos). Una flota de 4 camiones (T1..T4) debe transportar cargamento variado a otras tantas ciudades (C1..C4). El coste de adjudicar el transporte varía en función de la distancia y de la peligrosidad del trayecto y se resume en la tabla adjunta. Exponer un algoritmo que calcule de manera óptima a quién encargarle qué destino de manera que en total el coste sea mínimo.

La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste (0,5 punto). Según el esquema elegido hay que especificar, además:

Voraz: demostración de optimalidad. Divide y vencerás: preorden bien fundado. Exploración en grafos: descripción del árbol de búsqueda asociado.

Page 288: Examenes resueltos
Page 289: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Febrero 2008 (Segunda Semana) Cuestión 1 (2 puntos). En la práctica obligatoria del presente curso 2007/2008 se ha tenido que diseñar y desarrollar un algoritmo para resolver el problema del nonograma. Dado el cuadrado de 4x4 de la figura, trazar el algoritmo que lo resuelve tal como lo hace el desarrollado para la práctica y explicar cada paso. Hacer al menos 3 niveles y al menos 2 backtrakings. Restricciones del nonograma:

1 1 1 1 1 2 2 2 1 X X X 1 X 3 X X X 1 1 X X

Solución: En función del algoritmo desarrollado por el alumno en la práctica. Fila 1 Fila 2

X

X X X O

O

X X X X X O

X X O X

X

O X O O

O

O O X O O O

Page 290: Examenes resueltos

[ ]( )

( ) [ ] [ ][ ] [ ]( )

( )

,

,

Proc Flotar i T 1...n ;

i_padre := i div 2;Si i > 1 y T i T i_padre entonces

Intercambiar T i T i_padre ;

Flotar i_padre,T ;fFlotar;

<

Fila 3 Fila 4 Cuestión 2 (2 puntos). Sea T[1..n] con k elementos (k<n) un montículo de mínimos. Se pide programar una función “flotar” recursiva que dado un nuevo elemento T[k+1] restaure la propiedad de montículo en T. Una función iterativa que lo resuelva puntuará cero puntos.

X O

X X X O O X O O

X X X X X O O X X O X O

O X X X O X X O

X

X X X O

O

X O X X O O

X O O X X O O O

Page 291: Examenes resueltos

Cuestión 3 (2 puntos). Dado n potencia de 2, escribe un algoritmo recursivo que calcule en tiempo logarítmico el valor de an suponiendo que solo se pueden realizar multiplicaciones y que éstas tienen coste unitario. Demuestre el coste mediante la ecuación de recurrencia. No justifique el esquema usado, aplíquelo. fun exp (a:entero,n:natural) dev entero si n=1 entonces dev a sino si n=0 entonces dev 1 sino t exp(a,n DIV 2) dev t t fsiffun

←⋅

En este problema: a=1, b=2, k=0, luego el caso es ( ) ( )kT n n logn∈Θ por lo que el coste es ( ) ( )T n logn∈Θ

Problema (4 puntos). Una flota de 4 camiones (T1..T4) debe transportar cargamento variado a otras tantas ciudades (C1..C4). El coste de adjudicar el transporte varía en función de la distancia y de la peligrosidad del trayecto y se resume en la tabla adjunta. Exponer un algoritmo que calcule de manera óptima a quién encargarle qué destino de manera que en total el coste sea mínimo.

Solución: El problema de las asignaciones Seccion 9.7 Brassad&Bradley. Similar al problema 4.6 del libro Esquemas Algorítmicos: Enfoque metodológico y problemas resueltos. Gonzalo, J. Rodríguez, M. ejercicio 15.1, página 508 de Estructura de datos y métodos algorítmicos. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias. Montículo de mínimos (cota mejor la de menor coste)

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )b

k

k

log a

n

T n n logn

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Page 292: Examenes resueltos

El algoritmo es el siguiente:

Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

tipos nodo = reg sol[1..n]de 1..n k:0..n tiempo:real tiempo-opt:real prioridad asignado[1..n]de bool freg ftipos

fun camiones-rp(T[1..n,1..n]de real)dev (sol-mejor[1..n]de 1..n, tiempo-mejor:real) var X,Y: nodo,C:colapr[nodo],opt[0..n],pes[0..n]de real (opt,pes):= pre-calculo-estimaciones(T) generamos la Raíz Y.k:=0; Y.asignado[1..n]=[falso]; Y.tiempo:=0; Y. tiempo-opt:=opt[0] C:= cp-vacia(); añadir(C,Y) tiempo-mejor:= pes[0] mientras ¬es-cp-vacia?(C)^(minimo(C).tiempo-opt ≤ tiempo-mejor) hacer Y:= minimo (C); eliminar-min(C) generamos los hijos de Y X.k:=Y.k+1; X.sol:=Y.sol; X.asignado:=Y.asignado para t=1 hasta n hacer si ¬ X.asignado[t] entonces X.sol[X.k]:=t; X.asignado[t]:= cierto X.tiempo:= Y.tiempo + T[X.k,t] X.tiempo-opt:= Y.tiempo + opt[X.k] si X.tiempo-opt ≤ tiempo-mejor entonces si X.k = n entonces sol-mejor:=X.sol; tiempo-mejor:= X.tiempo sino añadir(C,X) tiempo-mejor:= min(tiempo-mejor, X.tiempo + pes[X.k]) fsi fsi X.asigando[t]:= falso fsi fpara fmientras ffun

fun pre-calculo-estimaciones (T[1..n, 1..n] de real) dev (opt[0..n], pes[0..n] de real) var rapido[1..n], lento[1..n] de real calculo de los minimos y maximos por filas para i = 1 hasta n hacer rapido[i]:= T[i,1] lento[i]:= T[i,1] para j = 2 hasta n hacer rapido[i]:= min(rapido[i],T[i,j]) lento[i]:= max(lento[i],T[i,j]) fpara fpara calculo de las estimaciones opt[n]:= 0; pes[n]:= 0; para i = n-1 hasta 0 paso -1 hacer opt[i]:= opt[i+1]+ rapido[i+1] pes[i]:= pes[i+1]+ lento[i+1] fpara ffun

Page 293: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2008 Cuestión 1 (1 punto). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 2 2 2 2 X X

1 2 X X X 1 1 2

Cuestión 2 (2 puntos). El algoritmo mergesort posee una complejidad T(n) ∈ Θ (n log n), describa y demuestre un caso en el que mergesort tiene una complejidad T(n) ∈ Θ (n2). Cuestión 3 (3 puntos). Considere un array A[1..n] ordenado y formado por enteros diferentes, algunos de los cuales pueden ser negativos. Escriba un algoritmo recursivo que calcule en tiempo logarítmico un índice i tal que 1 ≤ i ≤ n y T[i] = i , siempre que este índice exista, devolviendo -1 si no existe. Se supone que las operaciones elementales tienen coste unitario. Demuestre el coste mediante la ecuación de recurrencia. No justifique el esquema usado, aplíquelo. Problema (4 puntos). Una empresa de mensajería tiene n repartidores con distintas velocidades según el tipo de envío. Se trata de asignar los próximos n envíos, uno a cada repartidor, minimizando el tiempo total de todos los envíos. Para ello se conoce de antemano la tabla de tiempos T[1..n,1..n] en la que el valor t[i,j] corresponde al tiempo que emplea el repartidor i en realizar el envío j. Se pide: La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste (0,5 punto).

Page 294: Examenes resueltos
Page 295: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2008 (Original) Cuestión 1 (1 punto). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 2 2 2 2 X X

1 2 X X X 1 1 2

1 1 1 2 2 2 2 X X

1 2 X X X 1 1 X X 2 X X

Fila 3:

Fila 4:

X O

O X O O

O X X O X O

O X O X O X O O

X

X X X O

O

Page 296: Examenes resueltos

Cuestión 2 (2 puntos). El algoritmo mergesort posee una complejidad T(n) ∈ Θ (n log n), describa y demuestre un caso en el que mergesort tiene una complejidad T(n) ∈ Θ (n2). Solución: Si utilizamos como posición de corte el penúltimo o (segundo) elemento del vector de forma consecutiva, el coste será equivalente a: t (n) = t(n−1) + t(1) + g(n) , donde g(n) ∈ Θ(n) de forma que t (n) ∈ Θ (n2) Cuestión 3 (3 puntos). Considere un array A[1..n] ordenado y formado por enteros diferentes, algunos de los cuales pueden ser negativos. Escriba un algoritmo recursivo que calcule en tiempo logarítmico un índice i tal que 1 ≤ i ≤ n y T[i] = i , siempre que este índice exista, devolviendo -1 si no existe. Se supone que las operaciones elementales tienen coste unitario. Demuestre el coste mediante la ecuación de recurrencia. No justifique el esquema usado, aplíquelo. fun coincide (A: array[1..n], ini, fin:natural) dev entero lon = fin – ini + 1 si lon < 1 entonces dev -1 sino si lon = 1 entonces si A[ini] = ini entonces dev ini sino dev -1 sino pos = (fin – ini+1) div 2 si A[pos] = pos entonces dev pos sino si A[pos] < pos entonces dev coincide(A, pos+1, fin) sino dev coincide(A, ini, pos-1]) fsi fsi fsi fun Ecuación de recurrencia:

En este problema: a=1, b=2, k=0, luego el caso es ( ) ( )kT n n logn∈Θ por lo que el coste es ( ) ( )T n logn∈Θ

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )b

k

k

log a

n

T n n logn

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Page 297: Examenes resueltos

Problema (4 puntos). Una empresa de mensajería tiene n repartidores con distintas velocidades según el tipo de envío. Se trata de asignar los próximos n envíos, uno a cada repartidor, minimizando el tiempo total de todos los envíos. Para ello se conoce de antemano la tabla de tiempos T[1..n,1..n] en la que el valor t[i,j] corresponde al tiempo que emplea el repartidor i en realizar el envío j. Se pide: Determinar qué esquema algorítmico es el más apropiado para resolver el problema. Se trata de un problema de optimización con restricciones. Por tanto, podría ser un esquema voraz o un esquema de ramificación y poda. Sin embargo descartamos el esquema voraz porque no es posible encontrar una función de selección y de factibilidad tales que una vez aceptado un candidato se garantice que se va alcanzar la solución óptima. Se trata, por tanto, de un algoritmo de ramificación y poda. Escribir el esquema general. Función RamificaciónPoda (nodo_raíz) dev nodo Montículo:=montículoVacío(); cota:=acotar(nodo_raíz); poner((cota,nodo_raíz), Montículo); mientras no vacío(Montículo) hacer (cota, nodo):=quitarPrimero(Montículo); si solución(nodo) entonces devolver nodo; si no para cada hijo en compleciones(nodo) hacer cota:=acotar(hijo); poner((cota,hijo),Montículo); fpara; fsi; fmientras devolver Ø Indicar que estructuras de datos son necesarias. nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; filas_no_asignadas: lista de cardinal; coste: cardinal; Montículo de mínimos (cota mejor la de menor coste) Desarrollar el algoritmo completo. Las funciones generales del esquema general que hay que instanciar son: 1. a. solución(nodo): si se han realizado N asignaciones (último_asignado==N) 2. b. acotar(nodo,costes): nodo.coste + “mínimo coste de las columnas no asignadas” 3. c. compleciones(nodo,costes): posibilidades para la siguiente asignación (valores posibles para asignaciones[último_asignado+1])

Page 298: Examenes resueltos

4. Función asignación(costes[1..N,1..N]) dev solución[1..N] Montículo:=montículoVacío(); nodo.último_asignado=0; nodo.coste=0; cota:=acotar(nodo,costes); poner((cota,nodo),Montículo); mientras no vacío(Montículo) hacer (cota,nodo):=quitarPrimero(Montículo); si nodo.último_asignado==N entonces devolver nodo.asignaciones; si no para cada hijo en compleciones(nodo,costes) hacer cota:=acotar(hijo,costes); poner((cota,hijo),Montículo); fsi; fmientras

devolver ∅; Función acotar(nodo,costes[1..N,1..N]) dev cota cota:=nodo.coste; para columna desde nodo.último_asignado+1 hasta N hacer minimo=∞; para cada fila en nodo.filas_no_asignadas hacer si costes[columna,fila]<mínimo entonces mínimo:=costes[columna,fila]; fsi fpara cota:=cota+mínimo; fpara devolver cota; Función compleciones(nodo,costes[1..N,1..N]) dev lista_nodos lista:=crearLista(); para cada fila en nodo.filas_no_asignadas hacer hijo:=crearNodo(); hijo.último_asignado:=nodo.último_asignado+1; hijo.asignaciones=nodo.asignaciones; hijo.asignaciones[hijo.último_asignado]:=fila; hijo.coste:=nodo.coste+costes[hijo.último_asignado,fila]; hijo.filas_no_asignadas:=nodo.filas_no_asignadas; eliminar(fila,hijo.filas_no_asignadas); añadir(hijo,lista); fpara; devolver lista; Coste: En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 299: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2008 Reserva Cuestión 1 (1 punto). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 1 1 2 2 2 1 X X X

1 X 3

1 1 Cuestión 2 (3 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

Cuestión 3 (2 puntos). Aplique el algoritmo de Prim al siguiente grafo empezando por el nodo 1. Indique claramente en cada paso qué arista se selecciona, y la evolución de la solución.

Problema (4 puntos). Un cajero automático dispone de n tipos de billetes distintos teniendo cada uno de los n tipos un valor distinto. Se trata de calcular si es posible suministrar al cliente el valor exacto solicitado, y si este fuera el caso el sistema deberá suministrar el conjunto de billetes que forman una solución, además se desea que el sistema utilice el menor número de billetes posible. Se puede suponer que el número de billetes de cada tipo disponibles es finito. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste (0,5 punto).

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 3 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 3, k-1); r ← r + uno (n DIV 3, k+1); DEVOLVER (r); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 4 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 4, k-1); r ← r + dos (n DIV 4, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 4, k+2); DEVOLVER (r); FIN FIN

Page 300: Examenes resueltos
Page 301: Examenes resueltos
Page 302: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2008 (Reserva) Cuestión 1 (1 punto). Escribe el grafo asociado al espacio de soluciones del problema del nonograma, a partir del nodo que se presenta a continuación. Se supone que a partir de dicho nodo se van a comenzar a explotar la fila 3. (No puntúa la exploración por fuerza bruta de coste

2

2n ).

1 1 1 1 1 2 2

2 1 X X X 1 X 3

1 1

1 1 1 1 1 2 2

2 1 X X X 1 X 3 X X X

1 1 X X Fila 3 Fila 4

X O

X X X O O X O O

X X X X X O O X X O X O

O X X X O X X O

X

X X X O

O

X O X X O O

X O O X X O O O

Page 303: Examenes resueltos

Cuestión 2 (3 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

El procedimiento uno tiene: Una instrucción constante, que no tenemos en cuenta para el cálculo, o bien dos llamadas recursivas, ambas invocan la función con un tamaño n/3. La expresión queda T(n) = T(n/3) + T(n/3) lo que equivale a T(n) = 2T(n/3) + c. Aplicando la resolución genérica de las expresiones del tipo: T(n) = aT(n/b) + cnk

con k = 0, a=2 y b=3 queda que 2 > 30 y por tanto la función T(n) tiene un coste ( )3log 2nΘ

El procedimiento dos tiene: Una llamada recursiva de tamaño n/4, Otra llama recursiva de tamaño n/4, Un bucle en el que se repite n veces un cálculo consistente en llamar dos veces a una función h(n;r; k) de coste lineal, /*más una instrucción simple*/, y por último Una instrucción simple /* que no tenemos en cuenta para el calculo*/ y otra llamada recursiva de tamaño n/4. Sumando los términos nos sale T(n) = T(n/4) +T(n/4)+n (2n) +T(n/4), lo que equivale a T(n) = 3T(n/4) + 2n2 Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk y siendo 3 < 4 2 el coste es Θ(n2). a = 3, b = 4, k = 2

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 3 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 3, k-1); r ← r + uno (n DIV 3, k+1); DEVOLVER (r); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 4 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 4, k-1); r ← r + dos (n DIV 4, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 4, k+2); DEVOLVER (r); FIN FIN

Page 304: Examenes resueltos

Cuestión 3 (2 puntos). Aplique el algoritmo de Prim al siguiente grafo empezando por el nodo 1. Indique claramente en cada paso qué arista se selecciona, y la evolución de la solución.

PASO ARISTA EVOLUCION COMPONENTES

EVOLUCION SOLUCION

INICIO 1 2 3 4 5

- (1,3) (3,4) (2,3) (2,6) (5,6)

123456 1,32456 1,3,4256 1,2,3,456 1,2,3,4,65 1,2,3,4,5,6

∅ (1,3) (1,3), (3,4) (1,3), (3,4),(2,3) (1,3), (3,4),(2,3),( 2,6) (1,3), (3,4),(2,3),( 2,6),(5,6)

Proceso terminado porque sólo queda una única componente conexa Problema (4 puntos). Un cajero automático dispone de n tipos de billetes distintos teniendo cada uno de los n tipos un valor distinto. Se trata de calcular si es posible suministrar al cliente el valor exacto solicitado, y si este fuera el caso el sistema deberá suministrar el conjunto de billetes que forman una solución, además se desea que el sistema utilice el menor número de billetes posible. Se puede suponer que el número de billetes de cada tipo disponibles es finito. Solución: Se trata de un problema de optimización, por lo tanto descarto el esquema de vuelta atrás, descarto también el esquema de divide y vencerás ya que no se puede dividir el problema en subproblemas iguales. Puede resolverse por un esquema voraz o ramificación y poda, voy a descartar el voraz ya que auque es posible encontrar una función de selección y de factibilidad para resolver el problema no lo haría de una forma optima, por lo tanto utilizaré ramificación y poda. El problema es similar al Ejercicio 15.2, página 511 de Estructura de datos y métodos algorítmicos. El algoritmo es el siguiente:

tipos nodo = reg sol[1..n]de 0..1 k:0..n peso, beneficio:real beneficio-opt:real prioridad freg ftipos

2 5

7 6 10 8

1 3

4

1 3 4

2 5

6

2 5

7 6 10 8

1 3

4

1 3 4

2 5

6

Page 305: Examenes resueltos

fun calculo-estimaciones (P[1..n], V[1..n] de real, M: real, k: 0..n, peso, beneficio:real) dev (opt, pes: real) hueco := M-peso; pes := beneficio; opt := beneficio; j := k+1 mientras j ≤ n ^ P[j] ≤ hueco hacer podemos coger el objeto j entero hueco := hueco-P[j] opt := opt + V[j]; pes:= pes + V[j] j := j+1 ; fmientras si j ≤ n entonces quedan objetos por probar fraccionamos el objeto j (solucion voraz) opt := opt + (hueco/P[j]*V[j] extendemos a una solución en la versión 0/1 j := j+1 mientras j ≤ n ^ hueco > 0 hacer si P[j] ≤ hueco entonces hueco := hueco – P[j] pes := pes + V[j] fsi j := j+1 fmientras fsi ffun

fun cajero-rp(P[1..n], V[1..n]de real, M: real)dev (sol-mejor[1..n]de 0..1, beneficio-mejor:real)var X,Y: nodo,C:colapr[nodo] generamos raíz Y.k:=0; Y.peso :=0; Y.beneficio:=0; (Y.beneficio-opt,beneficio-mejor):= calculo-estimaciones(P, V, M, Y.k, Y.peso, Y.beneficio) C:= cp-vacia(); añadir(C,Y) mientras ¬es-cp-vacia?(C)^(minimo(C).beneficio-opt ≥ beneficio-mejor) hacer Y:= maximo (C); eliminar-max(C) X.k:=Y.k+1; X.sol:=Y.sol; probamos a meter el objeto en la mochila si Y.peso + P[X.k] ≤ M entonces es factible y, por tanto, las estimaciones coinciden con las de Y beneficio-opt(X) = beneficio-opt(Y) ≥ beneficio-mejor X.sol[X.k]:=1; X.peso:= Y.peso + P[X.k] X.beneficio:= Y.beneficio + V[X.k]; X.beneficio-opt := Y.beneficio-opt si X.k = n entonces beneficio(X) = beneficio-opt(X) ≥ beneficio-mejor sol-mejor:=X.sol; beneficio-mejor:= X.beneficio sino añadir(C,X) no se puede mejorar beneficio mejor fsi fsi probamos a no meter el objeto (siempre es factible) (X.beneficio-opt, pes) := calculo-estimaciones (P, V, M, X.k, Y.peso, Y.beneficio) si X.beneficio-opt ≥ beneficio-mejor entonces X.sol[X.k] := 0; X.peso := Y.peso X.beneficio := Y.beneficio si X.k = n enteonces sol-mejor := X.sol; beneficio-mejor := X.beneficio sino añadir(C,X) beneficio-mejor := max(beneficio-mejor, pes) fsi fsi fmientras ffun

Page 306: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Diciembre 2008 Cuestión 1 (2 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

Cuestión 2 (2 puntos). Dos amigos juegan a un sencillo juego de adivinación: uno de ellos piensa un número natural positivo y el otro debe adivinarlo preguntando solamente si es menor o igual que otros números. ¿Qué esquema algorítmico utilizaría para adivinar el número en tiempo logarítmico? Diseñe el algoritmo y escríbalo en pseudocódigo. (Resuelto en Estructuras de datos y métodos algorítmicos pag 312) Cuestión 3 (2 puntos). Inserte los valores 2,6,5,4,2,9,1,1 en un montículo de mínimos y muestre el montículo a cada paso. Problema (4 puntos). Se dispone de una cinta secuencial donde se almacenan programas. Los programas ocupan una longitud en la cinta. Cada programa Pi ocupa una longitud Li, lo que equivale a tardar un tiempo Ti en su lectura secuencial. Programe un algoritmo que calcule la disposición de los programas en la cinta de manera que se minimice el tiempo medio de acceso a cualquier programa Pi. 1. Elección del esquema más apropiado, el esquema general y explicación de aplicación al problema. (1 punto). 2. Descripción de las Estructuras de datos necesarias. (0,5 puntos) 3. Algoritmo completo a partir del refinamiento del esquema general. (2 puntos) 4. Estudio del coste del algoritmo desarrollado. (0,5 puntos)

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 2, k-1); r ← r + uno (n DIV 2, k+1); r ← r + uno (n DIV 2, k+2); DEVOLVER (1); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 2, k-1); r ← r + dos (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 307: Examenes resueltos
Page 308: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Diciembre 2008 Cuestión 1 (2 puntos). Hallar formalmente el coste de los siguientes algoritmos, siendo ( ) ( ), ,h n r k n∈Ο NOTA: Acertar a ojo se evalúa con cero puntos.

El procedimiento uno tiene: Una instrucción constante, que no tenemos en cuenta para el cálculo, o bien tres llamadas recursivas, ambas invocan la función con un tamaño n/2. //En el segundo y tercer caso de la llamada recursiva hay otra instrucción simple añadida. La expresión queda T(n) = T(n/2) + T(n/2) + T(n/2) lo que equivale a T(n) = 3T(n/2) + c. Aplicando la resolución genérica de las expresiones del tipo: T(n) = aT(n/b)+cnk

con k = 0, a=3 y b=2 queda que 3 > 20 y por tanto la función T(n) tiene un coste ( )2log 3nΘ

El procedimiento dos tiene: Una llamada recursiva de tamaño n/2, Otra llama recursiva de tamaño n/2, Un bucle en el que se repite n veces un cálculo consistente en llamar dos veces a una función h(n;r;k) de coste lineal, /*más una instrucción simple*/, y por último Una instrucción simple /* que no tenemos en cuenta para el calculo*/ y otra llamada recursiva de tamaño n/2. Sumando los términos nos sale T(n) = T(n/2) +T(n/2)+n (2n) +T(n/2), lo que equivale a T(n) = 3T(n/2) + 2n2 Aplicando la resolución genérica de las expresiones del tipo T(n) = aT(n/b) + cnk y siendo 3 < 2 2 el coste es Θ(n2). a = 3, b = 2, k = 2

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

PROCEDIMIENTO uno (n,k:entero):entero; VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← uno (n DIV 2, k-1); r ← r + uno (n DIV 2, k+1); r ← r + uno (n DIV 2, k+2); DEVOLVER (1); FIN FIN

PROCEDIMIENTO dos (n,k:entero):entero;VAR i,r:entero; COMIENZO SI n < 2 ENTONCES DEVOLVER(1); SINO COMIENZO r ← dos (n DIV 2, k-1); r ← r + dos (n DIV 2, k+1); PARA i ← 1 HASTA n HACER COMIENZO r ← h (n,r,i); r ← r + h (n,r-1,i); FIN r ← r + dos (n DIV 2, k+2); DEVOLVER (r); FIN FIN

Page 309: Examenes resueltos

Cuestión 2 (2 puntos). Dos amigos juegan a un sencillo juego de adivinación: uno de ellos piensa un número natural positivo y el otro debe adivinarlo preguntando solamente si es menor o igual que otros números. ¿Qué esquema algorítmico utilizaría para adivinar el número en tiempo logarítmico? Diseñe el algoritmo y escríbalo en pseudocódigo. (Resuelto en Estructuras de datos y métodos algorítmicos pag 312) Solución: Como el número a adivinar puede ser arbitrariamente grande, empezar por el 1 y seguir después en secuencia hasta alcanzar el número propuesto no es un método práctico. En su lugar, necesitamos hacer una búsqueda binaria, que nos permita reducir de forma más rápida el conjunto de candidatos. Sin embargo, el algoritmo de búsqueda binaria funciona con vectores de tamaño fijo y conocido, por lo que lo primero será encontrar alguna cota superior del número a adivinar, en principio una cota inferior es 1. Para encontrar dicha cota habrá que seguir un método que genere números cada vez más grandes y de modo que el incremento también aumente de forma rápida. A tal efecto, podemos utilizar, por ejemplo, las potencias de 2. Para adivinar el número utilizaremos una variación de la búsqueda binaria donde no necesitamos un vector porque se trabaja con un intervalo de enteros positivos y además siempre vamos a tener éxito. Esta nueva versión en lugar de recibir el número a buscar como argumento lo devuelve como resultado, para ello utiliza una función interna menor-igual que devuelve cierto si y solo si el número a adivinar es menor o igual que el propuesto como argumento. fun bus-bin2 (c,f) dev n:nat si c = f entonces dev c sino m = (c+f)div 2 si menor-igual (m) entonces dev bus-bin2(c,m) sino dev bus-bin2(m+1,f) fsi fsi ffun fun adivinar() dev n:nat encontrar cotas superior e inferior cinf = 1; csup = 1; mientras ¬ menor-igual(csup) hacer cinf = csup+1; csup = 2*csup; fmientras n = bus-bin2 (cinf,csup) ffun Aunque la función no recibe argumento alguno, su resultado depende del número oculto a adivinar, el cual determina el comportamiento de la función menor-igual. Si n es el número a adivinar, para determinar el intervalo donde hacer la búsqueda binaria se necesitan ⎡ ⎤ 1log += nm preguntas y el tamaño del intervalo donde hacer la búsqueda binaria es 2m . Por tanto la cantidad total de preguntas a realizar, en el caso peor está en )(lognΘ . Podríamos considerar otra base para las potencias, observando que cuanto mayor sea dicha base antes se encontrará la cota superior. Sin embargo hay que tener en cuenta que en general el intervalo que quedará para la búsqueda binaria será también mayor.

Page 310: Examenes resueltos

Cuestión 3 (2 puntos). Inserte los valores 2,6,5,4,2,9,1,1 en un montículo de mínimos y muestre el montículo a cada paso.

1. V=[2] 2. V=[2,6] 3. V=[2,6,5] 4. V=[2,4,5,6] 5. V=[2,2,5,6,4] 6. V=[2,2,5,6,4,9] 7. V=[1,2,2,6,4,9,5] 8. V=[1,1,2,2,4,9,5,6] Paso 1 Paso 2 Paso 3 Paso 4 Paso 5

Paso 6 Paso 7 Paso 8

2 2

6 5

2

6 5

2

4

6

5

2

2

6 4

2

2

6 4

5

9

1

2

6 4 5

2

9

1

1

2 4 5

2

9

6

Page 311: Examenes resueltos

Problema (4 puntos). Se dispone de una cinta secuencial donde se almacenan programas. Los programas ocupan una longitud en la cinta. Cada programa Pi ocupa una longitud Li, lo que equivale a tardar un tiempo Ti en su lectura secuencial. Programe un algoritmo que calcule la disposición de los programas en la cinta de manera que se minimice el tiempo medio de acceso a cualquier programa Pi. 1. Elección del esquema más apropiado, el esquema general y explicación de aplicación al problema. (1 punto). 2. Descripción de las Estructuras de datos necesarias. (0,5 puntos) 3. Algoritmo completo a partir del refinamiento del esquema general. (2 puntos) 4. Estudio del coste del algoritmo desarrollado. (0,5 puntos) 1. Elección del esquema: Se trata de un problema de optimización, por lo tanto descarto divide y vencerás y vuelta atrás. Me queda saber si puedo encontrar una función de selección para decidirme por un esquema voraz. Eligiendo a los programas por orden creciente de longitud, obtenemos una solución óptima, así puedo descartar ramificación y poda. fun voraz (C: conjunto) dev (S: conjunto) S ← ∅ mientras ¬ solucion (S) ∧ C ≠ ∅ hacer x ← Seleccionar (C) C ←C \ x si completable (S ∪ x) entonces S ← S ∪ x fsi dev S ffun Estructuras de datos: Tres vectores de enteros, un vector booleano y la función auxiliar ordenar índices. Algoritmo completo a partir del refinamiento del esquema general fun cinta (C[1..n]nat, D[1..n]nat) dev sol[1..n] bool

var F[1..n]nat ; I[1..n]1..n ; para i=1 hasta n hacer F[i]:= C[i]+D[i]; sol[i]:= falso; fpara I:= ordenar-indices(F) sol[I[1]]:= cierto; final := F[I[1]]; para i=2 hasta n hacer si C[I[i]]≥ final entonces sol[I[i]]:= cierto; final := F[I[i]]; fsi fpara ffun fun ordenar-indices(V[1..n])dev indice [1..n]1..n merge-indice(V,indice,1,n) ffun Estudio del coste El bucle voraz es de complejidad lineal respecto al número de clientes y el orden de complejidad del algoritmo completo corresponde al de la ordenación del vector de tiempos finales ( )nlognΘ .

Page 312: Examenes resueltos
Page 313: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2009 – Primera semana Cuestión 1 (1 punto). En la práctica obligatoria del presente curso 2008/2009 se ha tenido que diseñar y desarrollar un algoritmo para resolver el problema del puzzle Shikaku. Dibuje todas las complecciones de los niveles necesarios hasta llegar a una solución, indicando además en qué puntos se produce un backtracking. El punto de partida es la casilla marcada con una flecha, que contiene un 4. las casillas sombreadas indican que ya tienen asignado un rectángulo.

Cuestión 2 (2 puntos). Indique y justifique cuales de las siguientes afirmaciones sobre órdenes de complejidad son ciertas y cuales falsas: a) 35 2 2 3n n O(n )+ ∈ ; b) 3 25 23n ( n n )∈Θ + ; c) ( ( )) ( ( )) ( ) ( )t n t n t n nΟ = Ω => ∈Θ ; d) ( ( ) | 2 ) ( ( ) | 2 )kf n n k f n nΩ = ⊂ Ω = Cuestión 3 (3 puntos). Considere dos vectores f y g de n elementos que representan los valores que toman dos funciones en el intervalo [0..n-1]. Los dos vectores están ordenados, pero el primero f es un vector estrictamente creciente (f[0] < f[1] < … < f[n-1]), mientras que g es un vector estrictamente decreciente (g[0] > g[1] > … > g[n-1]). Las curvas que representan dichos vectores se cruzan en un punto concreto, y lo que se desea saber es si dicho punto está contenido entre las componentes de ambos vectores, es decir, si existe un valor i tal que f[i] = g[i] para 0 ≤ i ≤ n-1. Se pide una función recursiva de coste logarítmico que devuelva i si existe y -1 en otro caso. Se supone que las operaciones elementales tienen coste unitario. Demuestre el coste mediante la ecuación de recurrencia. No justifique el esquema usado, aplíquelo. La figura muestra un ejemplo en el que las gráficas se cruzan en i=8 que se corresponde con el valor 25 en ambas curvas.

Page 314: Examenes resueltos

Problema (4 puntos). Se dispone de n cubos identificados por un número del 1 al n. Cada cubo tiene impresa en cada una de sus caras una letra distinta. Se indica además una palabra de n letras. Se trata de colocar los n cubos uno a continuación de otro, de forma que con esta disposición se pueda formar la palabra dada. Como entre diferentes cubos puede haber letras repetidas, la solución puede no ser única o no existir. Se pide un algoritmo para encontrar una solución o indicar que no la hay. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2 puntos). 4. Estudio del coste (1 punto).

Page 315: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Febrero 2009 – Segunda semana Cuestión 1 (1 punto). En la práctica obligatoria del presente curso 2008/2009 se ha tenido que diseñar y desarrollar un algoritmo para resolver el problema del puzzle Shikaku. Dibuje todas las complecciones que tendría que explorar el algoritmo a partir de la situación mostrada en el tablero, para el nodo de la casilla marcada con una flecha, que contiene un 4 (sólo para ese nodo, y suponiendo que es el siguiente a considerar). Las casillas sombreadas indican que ya tienen asignado un rectángulo. Dibuje el tablero correspondiente para cada una de las complecciones.

Cuestión 2 (2 puntos). Responda a las siguientes cuestiones.

1. ¿Qué diferencias hay entre un montículo y un árbol binario de búsqueda? 2. Dibuje un montículo (el árbol) y un árbol binario de búsqueda con los siguientes nodos:

6, 12, 18, 20, 27, 34, 35. Cuestión 3 (3 puntos). Los residentes de una ciudad no quieren pavimentar todas sus calles, sino sólo aquellas que les permitan ir de una intersección a otra cualquiera de la ciudad con comodidad. Quieren gastarse lo menos posible en la pavimentación, teniendo en cuenta que el coste es directamente proporcional a la longitud de las calles que hay que pavimentar. El alcalde querría saber qué calles tiene que pavimentar para gastarse lo menos posible. 1. Indique qué esquema aplicarías para resolver el problema. Justifícalo y escribe el esquema general. 2. Explique los aspectos destacados de cómo resolverías el problema en función del esquema elegido (Por ejemplo: voraz: función de selección, demostración de optimalidad; divide y vencerás: tamaño del problema, cómo se divide del problema, subalgoritmo básico; vuelta atrás: descripción del espacio de búsqueda, compleciones; ramificación y poda: función de cota, compleciones…). 3. Indique el coste asociado y justifíquelo. NO se pide el algoritmo.

Page 316: Examenes resueltos

Problema (4 puntos). Tenemos un conjunto de n componentes electrónicas (c1,…cn) para colocar en n posiciones sobre una placa. Nos dan dos matrices N y D de dimensiones n x n, donde N[i,j] indica el número de conexiones necesarias entre la componente ci y la componente cj, y D[p,q] indica la distancia sobre la placa entre la posición p y la posición q (ambas matrices son simétricas y con diagonales nulas). Un cableado (x1,...xn) de la placa consiste en la colocación de cada componente ci en una posición distinta. La longitud total de este cableado viene dada por la fórmula:

Se pide un algoritmo para encontrar el cableado de longitud mínima. La resolución de este problema debe incluir, por este orden: 1. Elección del esquema más apropiado, el esquema general y explicación de su aplicación al problema (0,5 puntos). 2. Descripción de las estructuras de datos necesarias (0.5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste del algoritmo desarrollado (0.5 puntos).

Page 317: Examenes resueltos

Cuestión 1 (1 punto). En la práctica obligatoria del presente curso 2008/2009 se ha tenido que diseñar y desarrollar un algoritmo para resolver el problema del puzle Shikaku. Dibuje todas las complecciones que tendría que explorar el algoritmo a partir de la situación mostrada en el tablero, para el nodo de la casilla marcada con una flecha, que contiene un 4 (sólo para ese nodo, y suponiendo que es el siguiente a considerar). Las casillas sombreadas indican que ya tienen asignado un rectángulo. Dibuje el tablero correspondiente para cada una de las complecciones.

Solución:

6

4

4

6

4

4

6

Page 318: Examenes resueltos

Cuestión 2 (2 puntos). Responda a las siguientes cuestiones.

1. ¿Qué diferencias hay entre un montículo y un árbol binario de búsqueda? 2. Dibuje un montículo (el árbol) y un árbol binario de búsqueda con los

siguientes nodos: 6, 12, 18, 20, 27, 34, 35. Solución:

1. En un árbol binario de búsqueda el valor contenido en todos los nodos internos es mayor o igual que los valores contenidos en su hijo izquierdo o en cualquiera de los descendientes de ese hijo, y menor o igual que los valores contenidos en su hijo derecho o en cualquiera de los descendientes de ese hijo. Mientras que un montículo es un árbol binario esencialmente completo, en el que el valor de cada uno de los nodos internos es mayor o igual que los valores de sus hijos. Esto se denomina propiedad del montículo. A diferencia de un árbol binario de búsqueda, un montículo se puede implementar como un vector sin ningún puntero explícito.

2. Árbol binario de búsqueda: Montículo:

20

12 34

6 18 27 35

35

18 34

6 12 27 20

Page 319: Examenes resueltos

Cuestión 3 (3 puntos). Los residentes de una ciudad no quieren pavimentar todas sus calles, sino sólo aquellas que les permitan ir de una intersección a otra cualquiera de la ciudad con comodidad. Quieren gastarse lo menos posible en la pavimentación, teniendo en cuenta que el coste es directamente proporcional a la longitud de las calles que hay que pavimentar. El alcalde querría saber qué calles tiene que pavimentar para gastarse lo menos posible.

1. Indique qué esquema aplicarías para resolver el problema. Justifícalo y escribe el esquema general.

2. Explique los aspectos destacados de cómo resolverías el problema en función del esquema elegido (Por ejemplo: voraz: función de selección, demostración de optimalidad; divide y vencerás: tamaño del problema, cómo se divide del problema, subalgoritmo básico; vuelta atrás: descripción del espacio de búsqueda, compleciones; ramificación y poda: función de cota, compleciones…).

3. Indique el coste asociado y justifíquelo. NO se pide el algoritmo.

Solución: 1.- Las intersecciones de la ciudad se pueden considerar los vértices de un grafo y las calles de la ciudad las aristas con el coste asociado de pavimentación. Como no se indica nada al respecto en el enunciado, se puede considerar que las calles son de 2 direcciones y por lo tanto estamos ante un grado valorado no dirigido. El objetivo es encontrar un subgrafo que contenga todos los vértices, que siga siendo conexo y que el coste de pavimentación sea mínimo, por lo que se trata de encontrar el árbol de recubrimiento de coste mínimo. Este problema se resuelve con un esquema voraz cuyo esquema general es el siguiente: fun voraz(C:conjunto) dev (S:conjunto)

S C: conjunto de candidatos y S: conjunto solución

mientras solución(S) C hacer

x seleccionar(C)

C C \ x

si completable(S x) entonces

S S x fsi fmientras Si solucion(S) entonces dev S sino dev “no hay soluciones” fsi ffun

Page 320: Examenes resueltos

2. y 3.- En el libro base de la asignatura, sección 6.3, se describen dos algoritmos voraces, Kruscal y Prim, que solucionan este problema. La instanciación del esquema general al problema y el cálculo de costes están descritos y explicados en el libro. Problema (4 puntos). Tenemos un conjunto de n componentes electrónicas (c1,…cn) para colocar en n posiciones sobre una placa. Nos dan dos matrices N y D de dimensiones n x n, donde N[i,j] indica el número de conexiones necesarias entre la componente ci y la componente cj, y D[p,q] indica la distancia sobre la placa entre la posición p y la posición q (ambas matrices son simétricas y con diagonales nulas). Un cableado (x1,...xn) de la placa consiste en la colocación de cada componente ci en una posición distinta

i

. La longitud total de este cableado viene dada por la fórmula:

ji

ji xxDjiN ],[],[

Se pide un algoritmo para encontrar el cableado de longitud mínima. La resolución de este problema debe incluir, por este orden:

1. Elección del esquema más apropiado, el esquema general y explicación de su aplicación al problema (0,5 puntos).

2. Descripción de las estructuras de datos necesarias (0.5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5

puntos). 4. Estudio del coste del algoritmo desarrollado (0.5 puntos).

Solución: Estructuras de datos y métodos algoritmicos N. Martí Oliet, et al. pag 485. Indicaciones: Esquema: ramificación y poda. La solución del problema es un cableado en el que se asigna una posición xi a la componente i. Se tiene que cumplir que las posiciones asignadas sean válidas y que no se repitan, es decir, son permutaciones de 1,...,n. funcion ramificacion_poda (ensayo) dev ensayo ensayo es un nodo

m monticulo_vacio();

cota_superior cota_superior_inicial;

Page 321: Examenes resueltos

solucion primera_solucion; añadir_nodo(m, ensayo); asignamos tareas al agente 1

mientras vacio(m) hacer

nodo extraer_raiz(m); si valido(nodo) entonces están completas las asignaciones si coste_asig(nodo) < cota_superior entonces

solucion nodo;

cota_superior coste_asig(nodo) fsi si no

si cota_inferior(nodo) cota_superior entonces dev solucion si no para cada hijo en compleciones(nodo) hacer si cota_inferior(hijo) < cota_superior añadir_nodo(m, hijo) fsi fpara fsi fsi fmientras ffuncion Estructuras de datos: Mantendremos marcadores con las posiciones ya utilizadas y el coste del cableado que representa la solución parcial en la que nos encontramos.

nodo=tupla asignaciones: vector[1..N]; último_asignado: cardinal; componentes_no_asignadas: lista de cardinal; coste: real; coste_optimo: real

Montículo de mínimos (cota mejor la de menor coste) Cotas: Cota inferior: Sea cost el coste de la solución parcial (x1,...,xk), y sema minD el mínimo global de la matriz D. Entonces una cota inferior a la longitud del cableado de la solución es

cota_inf = cost + minD ∑j= k1

n

∑i= 1

j− 1

N [ i , j ]

Cota superior: Sea maxD el máximo global de la matriz D, entonces una cota superior es:

Page 322: Examenes resueltos

cota_sup = cost + maxD ∑j= k1

n

∑i= 1

j− 1

N [ i , j ]

Coste: El árbol de exploración tiene n niveles. En este caso únicamente podemos hallar una cota superior del coste del algoritmo por descripción del espacio de búsqueda. En el caso peor se generan (k-1) hijos por cada nodo del nivel k, habiendo n. Por tanto, el espacio a recorrer siempre será menor que n!.

Page 323: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2009 Cuestión 1 (1,5 puntos). ¿Para qué tipo de operaciones el montículo es una estructura adecuada? ¿Qué coste tiene asociado? Escribe el procedimiento flotar que flote el nodo i en un montículo T[1..n]. Cuestión 2 (1,5 puntos). Dado el siguiente grafo, rellene una tabla similar a la adjunta indicando paso a paso cómo el algoritmo de Prim halla un árbol de recubrimiento mínimo (ARM) asociado a dicho grafo, a partir del nodo 1.

Cuestión 3 (3 puntos).

a) ¿Qué sucede con la eficacia de los algoritmos de divide y vencerás si en lugar de utilizar un umbral para decidir cuando hay que volver al subalgoritmo básico, empleamos la recurrencia un máximo de r veces, para alguna constante r, y utilizamos después el subalgoritmo básico?

b) Se dispone de una bolsa de n monedas de oro y una de ellas es falsa. Lo único que distingue a la moneda falsa de las legales es su peso, aunque no hay seguridad de que éste sea mayor o menor que el de las legales. Para descubrir cual es falsa, se dispone de una balanza con dos platillos para comparar el peso de dos conjuntos de monedas. En cada pesada lo único que se puede observar es si la balanza queda equilibrada, si pesan más los objetos de la derecha o si pesan más los objetos de la izquierda. Indicad y demostrad informalmente cuantas pesadas hacen falta como mínimo, siendo n ≥3, para determinar cual es la moneda falsa y si pesa más o menos que las auténticas. No se pide el algoritmo.

Problema (4 puntos). Se quiere realizar en un soporte secuencial (cinta de dos caras) una recopilación de canciones preferidas. Se dispone de una lista de n canciones favoritas, junto con la duración individual de cada una. Lamentablemente, la cinta de T minutos no tiene capacidad para contener todas las canciones, por lo que se les ha asignado una puntuación (cuanto más favorita es, mayor es la puntuación). Se pretende obtener la mejor cinta posible según la puntuación, teniendo en cuenta que las canciones deben caber enteras y no es admisible que una canción se corte al final de una de las caras. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste del algoritmo desarrollado (0,5 punto).

Page 324: Examenes resueltos
Page 325: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2009 (Original) Cuestión 1 (1,5 puntos). ¿Para qué tipo de operaciones el montículo es una estructura adecuada? ¿Qué coste tiene asociado? Escribe el procedimiento flotar que flote el nodo i en un montículo T[1..n]. Para las operaciones de listas de prioridad dinámica: hallar el elemento prioritario de un conjunto (O(1)), eliminarlo (O(logn)), añadir un elemento en orden de prioridad (O(logn)). Libro página 188. Costes de los Montículos Función COSTE Vacío 1 Max 1 Min 1 Buscar 1 Añadir ( )O logn Borrar ( )O logn Hundir ( )O logn Flotar ( )O logn Fusionar ( )O n Cuestión 2 (1,5 puntos). Dado el siguiente grafo, rellene una tabla similar a la adjunta indicando paso a paso cómo el algoritmo de Prim halla un árbol de recubrimiento mínimo (ARM) asociado a dicho grafo, a partir del nodo 1.

PASO ARISTA Nodos Aristas ARM INICIO

1 2 3 4 5

- (1,5) (5,4) (4,3) (2,3) (4,6)

123456 1,52346 1,4,5236 1,3,4,526 1,2,3,4,56 1,2,3,4,5,6

∅ (1,5) (1,5), (5,4) (1,5), (5,4),(4,3) (1,5), (5,4),(4,3),( 3,2) (1,5), (5,4),(4,3),( 3,2),(4,6)

Proceso terminado porque sólo queda una única componente conexa

PROCEDURE Flotar (i:INTEGER; VAR T:TipoMonticulo) VAR j,k: INTEGER; BEGIN k ← i; REPETIR j ← k; IF (j>1) AND T [j DIV 2]< T[k]) THEN k ← DIV 2; Intercambia (T[j],T[k]); HASTA j = k; END Flotar;

Page 326: Examenes resueltos

Cuestión 3 (3 puntos). a) ¿Qué sucede con la eficacia de los algoritmos de divide y vencerás si en lugar de utilizar un

umbral para decidir cuando hay que volver al subalgoritmo básico, empleamos la recurrencia un máximo de r veces, para alguna constante r, y utilizamos después el subalgoritmo básico? (Solución: EDMA 11.14 Pág. 333)

b) Se dispone de una bolsa de n monedas de oro y una de ellas es falsa. Lo único que distingue a

la moneda falsa de las legales es su peso, aunque no hay seguridad de que éste sea mayor o menor que el de las legales. Para descubrir cual es falsa, se dispone de una balanza con dos platillos para comparar el peso de dos conjuntos de monedas. En cada pesada lo único que se puede observar es si la balanza queda equilibrada, si pesan más los objetos de la derecha o si pesan más los objetos de la izquierda. Indicad y demostrad informalmente cuantas pesadas hacen falta como mínimo, siendo n ≥3, para determinar cual es la moneda falsa y si pesa más o menos que las auténticas. No se pide el algoritmo. (Solución: EDMA 11.20 Pág. 344)

a) Si se utiliza la recurrencia un máximo de r veces antes de aplicar el subalgoritmo básico, el algoritmo resultante no mejorará de forma asintótica sobre el subalgoritmo básico desde el punto de vista de la notación Θ. Podrá ser un algoritmo más rápido que si no hubiera división, pero no más que un factor constante. b) Se puede dividir el conjunto inicial de monedas en 3 grupos iguales, dejando aparte 1 o las 2 que puedan sobrar. Se pesan y comparan los 3 grupos (2 pesadas). Si la moneda falsa está en uno de los 3 grupos, su peso no coincidirá con el de los otros 2, por lo que descartamos los 2 grupos que pesan igual quedándonos con el que pesa distinto y repitiendo el procedimiento. Si los 3 grupos pesan igual, la moneda está entre la o las que se apartaron y con una pesada de una de ellas con una auténtica se determina cuál es la falsa y si pesa más o menos. Por lo que harán falta O(2 log3(n)) pesadas. Problema (4 puntos). Se quiere realizar en un soporte secuencial (cinta de dos caras) una recopilación de canciones preferidas. Se dispone de una lista de n canciones favoritas, junto con la duración individual de cada una. Lamentablemente, la cinta de T minutos no tiene capacidad para contener todas las canciones, por lo que se les ha asignado una puntuación (cuanto más favorita es, mayor es la puntuación). Se pretende obtener la mejor cinta posible según la puntuación, teniendo en cuenta que las canciones deben caber enteras y no es admisible que una canción se corte al final de una de las caras. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste del algoritmo desarrollado (0,5 punto). 1. Elección del esquema: 1.- Ramificación y poda. Se trata de una optimización y no existe una función de selección de soluciones parciales que nos permita garantizar que dichas soluciones parciales construidas lleven a la óptima final, por lo que no se trata de un algoritmo voraz. Tampoco existe una forma de dividir el problema en subproblemas que se puedan resolver independientemente, por lo que tampoco es posible un esquema divide y vencerás.

Page 327: Examenes resueltos

Función RamificaciónPoda (ensayo) dev ensayo ensayo es un nodo m:= montículo_vacío(); cota_superior:= cota_superior_inicial; solucion:= primera_solucion; añadir_nodo(m,ensayo); mientras no vacío(m) hacer nodo:= extraer_raiz(m); si valido(nodo) entonces solución completa si coste_asig(nodo) < cota_superior entonces solucion:= nodo; cota_superior:= coste_asig(nodo) fsi si no si cota_inferior(nodo)≥ cota_superior entonces dev solucion si no para cada hijo en compleciones(nodo) hacer si cota_inferior(hijo)< cota_superior; añadir_nodo(m,hijo); fsi fpara; fsi; fmientras Se considera en cada etapa una canción y se considera grabarla en cada una de las dos caras, si hay espacio suficiente, así como la posibilidad de no grabarla en la cinta. La posibilidad de grabarla en la segunda cara sólo se plantea cuando la ocupación de las dos caras es distinta. Una cota superior podría ser la puntuación estimada considerando como espacio libre total la suma del espacio libre en cada cara y grabar el máximo posible de canciones, aunque alguna quede cortada. 2.- Se utiliza un montículo en el que cada nodo será necesario almacenar: • Solución parcial • Etapa • Puntuación-estimada • Puntuación acumulada • Ocupación de cada cara Además en un array tendremos las canciones con su puntuación y su duración. Por lo que la estructura de cada nodo sería un registro con los siguientes campos: Sol[1..n] de 0..2 K: 0..n Puntuación_acumulada: real Puntuación-estimada: real prioridad Ocupada[1..2] de real 3.- Una descripción detallada de la solución puede encontrarse en el texto de Estructuras de datos y métodos algorítmicos. N. Martí Oliet, Y. Ortega Mallén, J.A. Verdejo López. Prentice Hall, 2003. Sección 15.3, pag. 513 4.- Una estimación del coste es el tamaño del árbol de búsqueda, que en el peor caso crece como O(n!), ya que cada nodo del nivel k puede expandirse con las n − k canciones que quedan por considerar.

Page 328: Examenes resueltos
Page 329: Examenes resueltos

UNED ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

INGENIERÍA TÉCNICA DE SISTEMAS E INGENIERIA TÉCNICA DE GESTION

Programación III – Septiembre 2009 Reserva Cuestión 1 (2 puntos). Calcule el orden de complejidad del siguiente algoritmo en función del tamaño del problema. Justifique la respuesta aplicando las ecuaciones de recurrencia que corresponda.

[ ]( )[ ]

( )( )1 1

2 2

fun examen V 1..n de elemento, c, f : nat dev existe : bool, may : elemento

si c = f entonces existe, may := cierto, V c

sino m := c+ f div2

existe , may := examen V,c,m

existe , may ( )

( )

1

1 1

2

:= examen V,m+1, f existe := falso si existe entonces comprobamos el primer candidato

existe, may := comprobar V,may ,c, f ,may

fsi si ¬existe existe entonc∧

( )2 2

es comprobamos el segundo candidato

existe, may := comprobar V,may ,c, f ,may

fsi fsiffun

Considere que el coste de la función comprueba es del orden de f-c, donde f y c son dos de sus parámetros de llamada. Cuestión 2 (2 puntos). ¿Existe un algoritmo voraz para el problema de devolver el cambio con el menor número de monedas en cualquier sistema monetario? Justifique su respuesta: si existe indique cual es la función de selección y demuestre su optimalidad. Si no existe indique un contraejemplo para la función de selección que considere más plausible. Cuestión 3 (2 puntos). Dado el siguiente grafo, rellene la tabla adjunta (usando todas las filas que necesite) indicando paso a paso cómo el algoritmo de Dijkstra encuentra todos los caminos de menor coste desde el nodo 1.

Page 330: Examenes resueltos

Problema (4 puntos). Un robot se mueve en un edificio en busca de un anillo que no sabe dónde está. Se trata de implementar una función busca_tesoro que le ayude a encontrar el anillo y a salir después del edificio. El edificio debe representarse como una matriz de entrada a la función cuyas casillas contienen uno de los siguientes tres valores: A para “paso libre”, B para “paso estrecho” (no cabe el robot) y C para “anillo”. El robot sale de la casilla (1,1) y debe encontrar la casilla ocupada por el anillo. En cada punto, el robot puede tomar la dirección Norte, Sur, Este u Oeste siempre que no haya una pared. La función busca_tesoro debe devolver la secuencia de casillas que componen el camino de regreso desde la casilla ocupada por el anillo hasta la casilla (1,1). Suponga que la distancia entre casillas adyacentes es siempre 1. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste del algoritmo desarrollado (0,5 punto).

Page 331: Examenes resueltos

RESPUESTAS EXAMEN Programación III. Septiembre 2009 (Reserva) Cuestión 1 (2 puntos). Calcule el orden de complejidad del siguiente algoritmo en función del tamaño del problema. Justifique la respuesta aplicando las ecuaciones de recurrencia que corresponda.

[ ]( )[ ]

( )( )1 1

2 2

fun examen V 1..n de elemento, c, f : nat dev existe : bool, may : elemento

si c = f entonces existe, may := cierto, V c

sino m := c+ f div2

existe , may := examen V,c,m

existe , may ( )

( )

1

1 1

2

:= examen V,m+1, f existe := falso si existe entonces comprobamos el primer candidato

existe, may := comprobar V,may ,c, f ,may

fsi si ¬existe existe entonc∧

( )2 2

es comprobamos el segundo candidato

existe, may := comprobar V,may ,c, f ,may

fsi fsiffun

Considere que el coste de la función comprueba es del orden de f-c, donde f y c son dos de sus parámetros de llamada. Para calcular el coste podemos utilizar la siguiente recurrencia:

( )( )/

k

k

cnT n

aT n b cn

⎧⎪= ⎨+⎪⎩

, 1, nsi n bsi b

≤ <≥

( )( )( )( )log

log

b

k

k

a

n

T n n n

n

⎧Θ⎪⎪∈ Θ⎨⎪Θ⎪⎩

, , ,

k

k

k

si a bsi a bsi a b

<

=

>

Tenemos a=2, b=2, k=1; ( ) ( )logT n n n∈Θ

Cuestión 2 (2 puntos). ¿Existe un algoritmo voraz para el problema de devolver el cambio con el menor número de monedas en cualquier sistema monetario? Justifique su respuesta: si existe indique cual es la función de selección y demuestre su optimalidad. Si no existe indique un contraejemplo para la función de selección que considere más plausible. (Respuesta: Fundamentos de Algoritmia, pag. 211 y Esquemas algorítmicos Pág. 12). Sep 2003 (Reserva)

Page 332: Examenes resueltos

No. Para aplicar el esquema voraz, el problema ha de ser de optimización. Se debe distinguir un conjunto de candidatos y que la solución pase por ir escogiéndolos o rechazándolos. La función de selección debe asegurar que la solución alcanzada es la óptima. Si no, puede que hayamos confundido el problema con uno de exploración de grafos. En el problema de las monedas, la solución es óptima tomando el conjunto de monedas españolas (cuando se utilizaban pesetas, no euros como ahora), es decir, C = 100, 25, 10 5 1. Sin embargo, si tomamos las monedas inglesas en peniques C = 30,24,12,6,3,1, para un cambio de 48 peniques, nuestro algoritmo nos daría un conjunto solución S = 30,12,6, pero la solución óptima sería S = 24,24. Cuestión 3 (2 puntos). Dado el siguiente grafo, rellene la tabla adjunta (usando todas las filas que necesite) indicando paso a paso cómo el algoritmo de Dijkstra encuentra todos los caminos de menor coste desde el nodo 1.

Distancias desde 1 Nodo Precedente

PASO Nodo Seleccionado Nodo No Seleccionado 2 3 4 5 2 3 4 5 0 1 2,3,4,5 5 ∞ 6 20 1 1 1 1 1 1,2 3,4,5 5 12 6 20 1 2 1 1 2 1,2,4 3,5 5 9 6 16 1 4 1 4 3 1,2,3,4 5 5 9 6 11 1 4 1 3

Problema (4 puntos). Un robot se mueve en un edificio en busca de un anillo que no sabe dónde está. Se trata de implementar una función busca_tesoro que le ayude a encontrar el anillo y a salir después del edificio. El edificio debe representarse como una matriz de entrada a la función cuyas casillas contienen uno de los siguientes tres valores: A para “paso libre”, B para “paso estrecho” (no cabe el robot) y C para “anillo”. El robot sale de la casilla (1,1) y debe encontrar la casilla ocupada por el anillo. En cada punto, el robot puede tomar la dirección Norte, Sur, Este u Oeste siempre que no haya una pared. La función busca_tesoro debe devolver la secuencia de casillas que componen el camino de regreso desde la casilla ocupada por el anillo hasta la casilla (1,1). Suponga que la distancia entre casillas adyacentes es siempre 1. Solución: Febrero 2003 (Primera Semana) Solución: 5.1 Elección razonada del esquema algorítmico Como no se indica nada al respecto de la distancia entre casillas adyacentes, y ya que se sugiere utilizar únicamente una matriz, es lícito suponer que la distancia entre casillas adyacentes es siempre la misma (1, sin pérdida de generalidad). Por otra parte, no se exige hallar el camino más corto entre la entrada y el minotauro, sino que el enunciado sugiere, en todo caso, que el algoritmo tarde lo menos posible en dar una de las posibles soluciones (y ayudar a salir al robot cuanto antes).

Page 333: Examenes resueltos

Tras estas consideraciones previas ya es posible elegir el esquema algorítmico más adecuado. El tablero puede verse como un grafo en el que los nodos son las casillas y en el que como máximo surgen cuatro aristas (N, S, E, O). Todas las aristas tienen el mismo valor asociado (por ejemplo, 1). En primer lugar, el algoritmo de Dijkstra queda descartado. No se pide el camino más corto y si se hiciera, las particularidades del problema hacen que el camino más corto coincida con el camino de menos nodos y, por tanto, una exploración en anchura tendrá un coste menor siempre que no se visiten nodos ya explorados, como mucho se recorrerá todo el tablero una vez (coste lineal con respecto al número de nodos versus coste cuadrático para Dijkstra). En segundo lugar, es previsible esperar que el anillo no esté cerca de la entrada (estará en un nivel profundo del árbol de búsqueda) por lo que los posibles caminos solución serán largos. Como no es necesario encontrar el camino más corto, sino encontrar un camino lo antes posible, una búsqueda en profundidad resulta más adecuada que una búsqueda en anchura. En el peor de los casos en ambas habrá que recorrer todo el tablero una vez, pero ya que buscamos un nodo profundo, se puede esperar que en media una búsqueda en profundidad requiera explorar menos nodos que una búsqueda en anchura. Si se supone que el edificio es infinito entonces una búsqueda en profundidad no sería adecuada porque no garantiza que se pueda encontrar una solución. En este enunciado se puede presuponer que el edificio es finito. En tercer lugar, es posible que una casilla no tenga salida por lo que es necesario habilitar un mecanismo de retroceso. Por último, es necesario que no se exploren por segunda vez casillas ya exploradas anteriormente. Por estos motivos, se ha elegido el esquema de vuelta atrás. 5.2. Descripción del esquema usado Vamos a utilizar el esquema de vuelta atrás modificado para que la búsqueda se detenga en la primera solución y para que devuelva la secuencia de ensayos que han llevado a la solución en orden inverso (es decir, la secuencia de casillas desde el anillo hasta la salida). fun vuelta-atrás (ensayo) dev (es_solución, solución) si válido (ensayo) entonces solución ← crear_lista(); solución ← añadir (solución, ensayo); devolver (verdadero, solución); si no hijos ← crear_lista(); hijos ← compleciones (ensayo) es_solucion ← falso; mientras ¬ es_solución ∧ ¬ vacia (hijos) hijo ← primero (hijos) si cumple_poda (hijo) entonces (es_solución, solución) ← vuelta-atrás(hijo) fsi fmientras si es_solución entonces solución ← añadir (solución, ensayo); fsi devolver (es_solución, solución); fsi ffun

Page 334: Examenes resueltos

5.3 Estructuras de datos Para almacenar las casillas bastará un registro de dos enteros x e y. Vamos a utilizar una lista de casillas para almacenar la solución y otra para las compleciones. Para llevar control de los nodos visitados bastará una matriz de igual tamaño que el anillo pero de valores booleanos. Será necesario implementar las funciones de lista: • crear_lista • vacia • añadir • primero 5.4 Algoritmo completo Suponemos “anillo” inicializado con la configuración del anillo y ”visitados” inicializado con todas las posiciones a falso. tipoCasilla = registro x,y: entero; fregistro tipoLista fun vuelta-atrás ( anillo: vector [1..LARGO, 1..ANCHO] de entero; casilla: tipoCasilla visitados: vector [1..LARGO, 1..ANCHO] de booleano; ) dev (es_solución: booleano; solución: tipoLista) visitados [casilla.x, casilla.y] ← verdadero; si anillo[casilla.x, casilla.y] == 2 entonces solución ← crear_lista(); solución ← añadir (solución, casilla); devolver (verdadero, solución); si no hijos ← crear_lista(); hijos ← compleciones (anillo, casilla) es_solución ← falso; mientras ¬ es_solución ∧ ¬ vacia (hijos) hijo ← primero (hijos) si ¬ visitados [hijo.x, hijo.y] entonces (es_solución, solución) ← vuelta-atrás (anillo,hijo,visitados); fsi fmientras si es_solución entonces solución ← añadir (solución, casilla); fsi devolver (es_solución, casilla); fsi ffun En el caso de encontrar al anillo se detiene la exploración en profundidad y al deshacer las llamadas recursivas se van añadiendo a la solución las casillas que se han recorrido. Como se añaden al final de la lista, la primera será la del anillo y la última la casilla (1,1), tal como pedía el enunciado. La función compleciones comprobará que la casilla no es una pared y que no está fuera del edificio

Page 335: Examenes resueltos

fun compleciones ( anillo: vector [1..LARGO, 1..ANCHO] de entero; casilla: tipoCasilla) dev tipoLista hijos ← crear_lista(); si casilla.x+1 <= LARGO entonces si anillo[casilla.x+1,casilla.y] <> 1 entonces casilla_aux.x=casilla.x+1; casilla_aux.y=casilla.y; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.x-1 >= 1 entonces si anillo[casilla.x-1,casilla.y] <> 1 entonces casilla_aux.x=casilla.x-1; casilla_aux.y=casilla.y; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.y+1 <= ANCHO entonces si anillo[casilla.x,casilla.y+1] <> 1 entonces casilla_aux.x=casilla.x; casilla_aux.y=casilla.y+1; hijos ← añadir (solución, casilla_aux); fsi fsi si casilla.y-1 >= 1 entonces si anillo[casilla.x,casilla.y-1] <> 1 entonces casilla_aux.x=casilla.x; casilla_aux.y=casilla.y-1; hijos ← añadir (solución, casilla_aux); fsi fsi ffun 5.5 Estudio del coste Todas las operaciones son constantes salvo la llamada recursiva a vuelta-atrás. En cada nivel, pueden realizarse hasta 4 llamadas. Sin embargo, las llamadas no se realizan si la casilla ya ha sido visitada. Esto quiere decir que, en el caso peor, sólo se visitará una vez cada casilla. Como las operaciones para una casilla son de complejidad constante, la complejidad será O(ANCHO*LARGO), lineal con respecto al número de casillas. La resolución del problema debe incluir, por este orden: 1. Elección razonada del esquema algorítmico mas eficiente para resolver el problema (0,5 puntos). 2. Estructuras de datos (0,5 puntos). 3. Algoritmo completo a partir del refinamiento del esquema general (2,5 puntos). 4. Estudio del coste del algoritmo desarrollado (0,5 punto).

Page 336: Examenes resueltos