Académique Documents
Professionnel Documents
Culture Documents
DNI: 00000000A
Tel. 001 002 003
Email: nombre@email.com
Centro Asociado: xxx
PED 1
MENSAJERA
URGENTE
PREDA - CURSO 2013/14
Prctica 1 de la asignatura Programacin y Estructuras de Datos
Avanzadas (cd. 71902019)
NDICE DE CONTENIDO
Contenido
Enunciado de la practica: Mensajera urgente ______________________________________________________ 1
Esquema algortmico utilizado y como se aplica al problema. _____________________________________ 2
Demostracion de optimalidad ________________________________________________________________________ 4
Coste computacional del algoritmo __________________________________________________________________ 5
Alternativas al esquema utilizado ____________________________________________________________________ 6
Divide y Venceras ______________________________________________________________________________________________ 6
Vuelta Atras ____________________________________________________________________________________________________ 6
Ramificacion y poda ___________________________________________________________________________________________ 8
Pagina 1
3.
4.
5.
Siguiendo estos pasos, se puede ya esbozar el algoritmo voraz que utilizaremos para resolver el
problema, que sera el siguiente:
tipo Vector = matriz[1..G-1] de booleano
fun express(DG: matriz[1..G-1] de natural, n,G: natural): Vector
var
solucion: Vector
fvar
para i 1 hasta G1 hacer
solucion[i] falso
fpara
km 0
Pagina 2
Donde n es la distancia maxima que puede recorrerse sin repostar, G el numero de gasolineras del
trayecto incluyendo el punto de origen y de destino como tales, y DG es un vector cuyo elemento i-simo
contiene la distancia entre la gasolinera i y la i+1. En el vector solucin cada elemento i-simo sera
verdadero o falso en funcion de si debe repostarse o no en la gasolinera i. Este vector no contempla
elementos para las gasolineras de los puntos de origen y destino ya que estan implcitos en la solucion
(se parte con el deposito lleno y siempre se llega (se para) al destino).
Pagina 3
Pagina 4
Pagina 5
DIVIDE Y VENCERS
La estrategia de Divide y Vencers se basa en la resolucion recursiva del problema, descomponiendolo en
subproblemas de su mismo tipo, hasta que estos llegan a ser lo suficientemente sencillos como para
resolverse directamente.
Basicamente, los pasos que se han de dar en la aplicacion de este esquema son:
1.
2.
3.
Plantear el problema de forma que pueda ser descompuesto en subproblemas del mismo tipo, pero
de menor tamano.
Resolver independientemente todos los subproblemas, bien directamente si es posible, o bien de
forma recursiva, volviendo a dividirlos en subproblemas mas pequenos.
Combinar las soluciones obtenidas en el paso anterior para obtener la solucion del problema
original.
Dicho esto, habra una forma de aplicar este esquema al problema de mensajera urgente que estamos
tratando.
En un primer paso, siempre que el problema no se pueda resolver de forma directa, tendramos que ir
dividiendo el vector DG, que contiene las distancias entre gasolineras, hasta dar con subvectores que
puedan ser recorridos de principio a fin sin repostar. Ademas, para garantizar una solucion optima
(menor numero posible de gasolineras en las que repostar), no se podra dividir el problema en
subproblemas de forma arbitraria, sino que habra que ir seleccionando esas divisiones de forma
cuidadosa. La unica forma de garantizar que las divisiones sean las adecuadas, es precisamente aplicar
un esquema voraz para seleccionarlas dividiendo el vector en dos subvectores, uno conteniendo un
tramo que pueda recorrerse sin repostar desde el punto de partida, y otro conteniendo el resto. A
continuacion, si ese vector con el resto tampoco puede resolverse de forma directa volver a dividirlo a su
vez de la misma forma, y as continuamente hasta alcanzar el destino. Finalmente, la solucion general
sera la formada por el conjunto de todos los elementos que esten en la ultima posicion de cada uno de
los subvectores que se han ido generando.
En el fondo, aplicando este esquema de esta forma (que es la unica que garantiza una solucion optima)
estamos haciendo lo mismo que si usaramos un algoritmo voraz. Y pese a que ambos tengan el mismo
coste temporal O(n), seguramente una implementacion siguiendo el esquema de Divide y Vencers sera
mas complicada de realizar en la practica.
VUELTA ATRS
En el esquema de vuelta atrs se recurre a una busqueda exhaustiva de las soluciones, generando un
grafo (generalmente representado en forma de arbol) que contenga todas las soluciones posibles, para
Pagina 6
En el se ha incluido la distancia que habra que recorrer para alcanzar un nodo desde otro. Tambien a la
izquierda de cada nodo, en color gris, aparece el orden en el que se van expandiendo los diferentes
nodos segun el algoritmo, siendo el orden como si de un recorrido en profundidad se tratase.
En cuanto a los costes, supongamos el caso peor que pueda darse, que sera cuando se pueda llegar a
cualquier gasolinera xi+j del trayecto desde la gasolinera xi. O, dicho de otro modo, cuando la distancia
entre el punto de origen y el de destino puede recorrerse sin tener que parar a repostar. Para
representar el arbol considerando el caso peor, necesitaremos un total de 2G-1 nodos. Por lo tanto, los
costes tanto espacial como temporal si usaramos este esquema para resolver el problema, seran O(2G-1),
Pagina 7
RAMIFICACIN Y PODA
Segun el libro de texto de la bibliografa basica de la asignatura (Programacion y Estructuras de Datos
Avanzadas, Lourdes Araujo Serna, p. 185), este esquema ser menos eficiente que el voraz cuando ambos
se pueden utilizar para realizar la optimizacin, por lo que su aplicacin est indicada slo cuando no se
conoce un algoritmo voraz vlido para el problema. Por lo tanto deberamos descartar su uso
inmediatamente.
De todos modos y como ejercicio meramente informativo, vamos a suponer que no hemos sido capaces
de demostrar la optimalidad del algoritmo voraz, y a plantear a grandes rasgos como se podra aplicar
este esquema a la resolucion del problema.
Para poder plantear el algoritmo lo primero que se necesita es definir las cotas tanto inferior o
estimacion optimista, como superior o estimacion pesimista. Sean d la distancia que hay entre la
gasolinera que estemos tratando y el destino final, y n la distancia maxima que puede recorrerse sin
repostar.
Una estimacion optimista sobre el numero de gasolineras en las que parar a repostar, sera (d/n) + p,
donde p sera el numero de paradas que lleva realizadas hasta ese momento. Sera una estimacion
demasiado optimista, inferior al valor alcanzable en la practica, ya que de lo que se trata es de
minimizar el numero de paradas del trayecto. Hay que anadir que utilizando esta funcion se esta
considerando el punto de destino como parada, aunque luego en la solucion final del problema se
descarte.
En cuanto a la estimacion pesimista, usaremos el numero de paradas que resultaran de aplicar el
algoritmo voraz, incluyendo tambien punto de destino como parada. Ya sabemos que en realidad esta es
una solucion optima al problema, pero como digo supondremos que no hemos sido capaces de
demostrar su optimalidad, y por lo tanto no sabemos si puede mejorarse esta cota o no.
Vamos a utilizar tambien un montculo de mnimos ordenado segun el valor de la estimacion optimista
calculada para cada uno de sus nodos. Cada nodo del montculo representara una gasolinera y una
solucion parcial del recorrido, indicando en que gasolineras se ha parado a repostar antes de llegar
hasta la que se este tratando en el nodo actual. Esta solucion parcial del nodo estara representada a su
vez por un vector booleano, indicando con un 1 o un 0 en su posicion i-esima si se debe parar o no en la
gasolinera i. Ademas, tambien incluiremos en el registro de cada nodo su estimacion optimista, el ndice
de la gasolinera que estamos tratando (k), el numero de paradas que se han hecho hasta el momento, la
Pagina 8
A este nodo le anadimos dos hijos, uno considerando que se debe parar en la primera gasolinera, y otro
considerando lo contrario, de la siguiente manera:
Pagina 9
Tras generar estos dos primeros nodos, vemos que en ninguno su estimacion optimista supera la cota
generada inicialmente, y por lo tanto no hay que podar. Para el nodo 2, debemos calcular de nuevo la
estimacion pesimista puesto que se ha realizado una parada, cuyo resultado es 2. Como no es inferior a
la cota actual, no hay que actualizarla (ademas dejo senalado ya que esto no sucedera en todo el
desarrollo, puesto que sabemos que utilizando un algoritmo voraz llegamos a la solucion optima, as que
no volvere a comentarlo). De estos dos nodos, el de menor estimacion optimista es el N1, por lo que sera
el siguiente en tratarse.
El nodo N3 debe podarse puesto que, a pesar de que su estimacion optimista no supere la cota, resulta
imposible alcanzar desde la gasolinera que representa a la siguiente sin hacer la parada. Por lo tanto nos
Pagina 10
El nodo N6, que representa una ruta en la cual se para en las gasolineras 2 y 3, obtiene una estimacion
optimista de 2,25, un valor superior (peor) a la cota y por lo tanto debe podarse, ya que nunca
alcanzaremos una solucion optima a traves de la solucion parcial que representa. En cambio el nodo N6
s tiene una estimacion optima inferior a la cota, debe introducirse en el montculo y como es el de
menor valor de los todava no tratados, sera el siguiente en procesarse:
Pagina 11
En esta nueva expansion podamos el nodo N9 puesto que su estimacion optimista supera a la cota, y
continuamos expandiendo el nodo N8.
Pagina 12
En este punto volvemos a llegar al final del recorrido, y al igual que en la vez anterior descartamos
directamente el nodo que no contempla el punto de destino como parada. El nodo restante N13
representa otra posible solucion que ademas tiene el mismo numero de paradas, 2.
Con este esquema hemos llegado por un lado a la misma solucion optima a la que se llegara aplicando
un esquema voraz, representada por el nodo N7, y a otra solucion diferente pero igual de optima,
representada por el nodo N13. En una pararemos en la segunda gasolinera de la ruta, y en la otra en la
primera, y ambas llegaran al destino realizando una unica parada (sin contar la del destino, tal y como
se pide en el enunciado del problema).
Este montculo que vamos construyendo tiene tantos niveles como gasolineras del problema, G, y en el
caso peor, cada nodo se ramificara en otros dos nodos por lo que se construiran un total de 2 G 1
nodos, y esto implica que el coste temporal de este algoritmo sera O(2G).
Es un coste algo peor que el obtenido usando un algoritmo de vuelta atras, y mucho peor que el del
algoritmo voraz, tal y como era de esperar, por lo que no sera recomendable usarlo bajo ninguna
circunstancia.
Pagina 13
Generar un archivo con un numero dado de gasolineras, y con distancias aleatorias entre ellas.
Ejecutar el programa usando este archivo como entrada y recuperar el tiempo que tarda el
algoritmo en resolver el problema.
Repetir los pasos 1 y 2 diez veces, descartar los tiempos maximo y mnimo obtenidos, y hacer una
media con el tiempo de los ocho restantes.
Este proceso se ha seguido para tratar problemas con un numero ascendente de gasolineras. Por
ejemplo, la salida de una de estas pruebas para ficheros con 10 gasolineras es la siguiente:
0.019282 ms
2 4 6 7 8
0.005598 ms
1 2 3 4 6 7
0.005287 ms
1 2 3 4 5 6
0.004976 ms
1 2 3 4 5 6
0.005287 ms
1 2 3 5 8
0.005287 ms
1 3 5 7 8
0.005287 ms
2 5 6 7 8
0.005287 ms
1 3 5 6 7
0.006842 ms
1 2 4 6 7 8
0.004976 ms
1 2 3 4 6
con 10 gasolineras.
con
8
con
8
con
8
con
10 gasolineras.
10 gasolineras.
10 gasolineras.
10 gasolineras.
con 10 gasolineras.
con 10 gasolineras.
con 10 gasolineras.
con 10 gasolineras.
con 10 gasolineras.
De los 10 tiempos obtenidos descartaramos el mayor y el menor, y con el resto hacemos una media, con
lo que nos queda que para 10 gasolineras, el tiempo de ejecucion es de 0,005481 ms.
Los datos obtenidos mediante esta batera de pruebas son los que se muestran en las tablas siguientes:
Pagina 14
Tiempo
0.003732 ms
0.005287 ms
0.010885 ms
0.02488 ms
0.043541 ms
0.091747 ms
0.187848 ms
0.351126 ms
0.629788 ms
Gasolineras
1.000.000
1.500.000
2.000.000
2.500.000
3.000.000
4.000.000
5.000.000
6.000.000
7.500.000
Tiempo
14.033853 ms
21.37173 ms
28.35600 ms
34.723864 ms
40.566118 ms
57.804581 ms
64.351887 ms
76.599008 ms
95.942984 ms
Al ir recopilando los tiempos me he encontrado con un problema. A partir de considerar cierto numero
de gasolineras, el tiempo misteriosamente deja de incrementarse de forma lineal. Y no es que empeore
precisamente, sino al contrario. Si tomamos por ejemplo el tiempo que tarda la ejecucion con 100
gasolineras, 0,043 ms, si se siguiese una progresion lineal directa respecto al numero de gasolineras, al
considerar 1.000.000 de gasolineras este tiempo debera ser del orden de 0,043x10.000 = 430 ms. Pero
como se ve en la segunda tabla, el tiempo obtenido en la practica ha sido de 14,03 ms.
En realidad no se a que es debido. Como para valores grandes de G (el numero de gasolineras), se debe
acceder a vectores con muchos elementos, pense que podra ser debido al tiempo que lleva acceder a
estos elementos, as que he probado a utilizar diferentes estructuras de datos para almacenar los
vectores tanto de las gasolineras como de las soluciones, usando arrays, listas, colas/pilas, e incluso
hashmaps. Se supone que en una cola o pila los tiempos para insertar un elemento o acceder a su
cabeza/cola son constantes, O(1), pero aun as el problema sigue presente.
La cada brusca del tiempo de ejecucion ocurre, en mi equipo de pruebas, cuando consideramos un valor
de G a partir de las 500.000 gasolineras aproximadamente. He buscado informacion sobre el tema pero
no he encontrado nada, aunque estoy casi convencido de que tiene que ver de algun modo con la forma
en la que java trata las estructuras de datos utilizadas.
Teniendo esto presente, se puede observar que para valores de G que esten dentro de un rango de
similar orden de magnitud, el tiempo de ejecucion es efectivamente lineal con respecto a G, O(G) tal y
como se haba previsto teoricamente. En las graficas de la pagina siguiente se aprecia perfectamente.
Pagina 15
Tabla 1
0,7
0,6
0,5
0,4
0,3
0,2
0,1
0
0
500
1000
1500
2000
2500
Tabla 2
120
100
80
60
40
20
0
0
Pagina 16
1.000.000
2.000.000
3.000.000
4.000.000
5.000.000
6.000.000
7.000.000
8.000.000
Pagina 17
Pagina 18
Pagina 19
Pagina 20
Pagina 21
Pagina 22
Pagina 23
Pagina 24
Pagina 25