Tema5 PC
Tema5 PC
Métodos algorítmicos de
resolución de problemas
Índice
Esquema 3
Ideas clave 4
5.1. Introducción y objetivos 4
5.2. Algoritmos de ordenación 6
5.3. Algoritmos de búsqueda 15
5.4. Algoritmos voraces 18
© Universidad Internacional de La Rioja (UNIR)
A fondo 40
Test 41
Esquema
© Universidad Internacional de La Rioja (UNIR)
El algoritmo más famoso es el algoritmo de Euclides (siglo III a. C.) para el cálculo del
máximo común divisor de dos números enteros.
En este tema se verán algunos algoritmos según su funcionalidad, que puede ser
ordenar y buscar, entre otros. Para algunos se presentarán distintas técnicas. Se
revisarán, así mismo, algunas técnicas de programación dinámica y heurísticas.
Método de la burbuja
Se trata del procedimiento de ordenación más conocido. Está considerado como uno
de los algoritmos de ordenación menos eficientes y solo se recomienda para ordenar
listas de datos pequeñas, de tamaño máximo 1 000.
están ordenados, los intercambia. Tras cada pasada, el dato de valor más grande
queda en su lugar.
Figura 1. Código y resultado del algoritmo de ordenación burbuja. Fuente: elaboración propia.
Vean el uso de la declaración de una variable global usada por la función, pero
que pertenece al ámbito global y, por tanto, se puede obtener su valor fuera
de ella tras la ejecución. Esto es un recurso que no se considera de muy buena
Figura 2. Código y resultado del algoritmo de ordenación por selección. Fuente: elaboración
propia.
En la tabla 3 se muestra la ejecución del algoritmo, donde cada fila representa una
© Universidad Internacional de La Rioja (UNIR)
iteración.
Figura 3. Código y resultado del algoritmo de ordenación por inserción. Fuente: elaboración
propia.
Consiste en dividir la lista en dos sub-listas de tamaño similar y ordenar cada una
de ellas usando la recursividad. Posteriormente, se mezclan las dos sub-listas
ordenadas manteniendo el orden.
Figura 4. Código y resultado del algoritmo de ordenación por mezcla. Fuente: elaboración propia.
Para analizar la complejidad del algoritmo se debe considerar que la división en dos
matrices requiere tiempo lineal. Fusionar también requiere tiempo lineal, de forma
© Universidad Internacional de La Rioja (UNIR)
𝑛 𝑛
que (𝑛) = 𝑡 ( 2 ) + 𝑡 (2 ) + 𝑔(𝑛) donde 𝑔(𝑛) ∈ Θ(𝑛).
𝑛
Por tanto, se produce una recurrencia de la forma 𝑡(𝑛) = 2𝑡 ( 2) + 𝑔(𝑛).
𝛩(𝑛𝑘 ) 𝑠𝑖 𝑙 < 𝑏 𝑘
𝑛
(𝑛) ∈ {𝛩(𝑛𝑘 𝑙𝑜𝑔 𝑛) 𝑠𝑖 𝑙 = 𝑏 𝑘 , 𝑠𝑖𝑒𝑛𝑑𝑜 𝑡(𝑛) = 𝑙𝑡 ( ) + 𝑔(𝑛), (1)
𝑏
𝛩(𝑛𝑙𝑜𝑔𝑏 𝑙 ) 𝑠𝑖 𝑙 > 𝑏 𝑘
Consiste en dividir la lista en dos sub-listas de tamaño similar. La mayor parte del
trabajo no recursivo se invierte en crear las sub-listas y no en la combinación de ellas.
La mezcla de las dos sub-listas es más eficiente si se cuenta con un espacio adicional
que se pueda usar como centinela.
© Universidad Internacional de La Rioja (UNIR)
Búsqueda secuencial
Busca un elemento dentro de una lista comenzando por el primero de ellos. Luego,
recorre la lista hasta que lo encuentra o hasta que no quedan más elementos por
consultar.
Figura 5. Código y resultado del algoritmo de búsqueda secuencial. Fuente: elaboración propia.
Este algoritmo requiere, en el peor de los casos, un tiempo que está en 𝛩(𝑖), donde
𝑖 es el índice en el que está el elemento. Por tanto, está en 𝛰(𝑛) en el peor de los
casos, siendo 𝑛 el número de elementos de la lista y en 𝛰(1) en el mejor caso.
© Universidad Internacional de La Rioja (UNIR)
Búsqueda binaria
Es uno de los más sencillos en el que se aplica una técnica de «divide y vencerás».
Parte de la base que la lista debe estar ordenada y va reduciendo el espacio o sección
de búsqueda descartando segmentos de ese espacio en los que es seguro que el valor
no va a estar. Inicialmente, el espacio de búsqueda es la lista total.
El tiempo que requiere una llamada recursiva de este algoritmo es 𝑡(𝑚) donde 𝑚 =
𝑢𝑙𝑡𝑖𝑚𝑜 − 𝑝𝑟𝑖𝑚𝑒𝑟𝑜 + 1, que es el número de elementos que quedan para la
búsqueda, y el tiempo requerido para la primera llamada es 𝑡(𝑛), que es el tamaño
de la lista.
Por tanto, cuando el número de elementos que quedan por buscar en una llamada
recursiva es mayor que uno requiere una cantidad constante de tiempo, además de
𝑚
la llamada recursiva con 𝑚/2. Esto quiere decir que 𝑡(𝑚) = 𝑡 ( 2 ) + 𝑔(𝑚) con
0 se concluye que 𝑡(𝑚) ∈ Θ(log 𝑚). Luego, este algoritmo requiere un tiempo
logarítmico, incluso en el caso mejor.
Existe una función que comprueba si se ha encontrado una solución factible, que
será un subconjunto de los candidatos que satisfacen ciertas restricciones.
Existe una función de selección que permite escoger un nuevo candidato de los
que quedan por comprobar.
Es una técnica ascendente, estos algoritmos comienzan resolviendo los casos más
sencillos y combinan las soluciones para resolver casos cada vez mayores hasta
obtener la solución del problema original.
Los datos que se necesitan conocer para describir cada etapa son pocos.
En cada capa se cumplen una serie de condiciones que determina el estado del
sistema asociado.
Se resuelven todos los subcasos, para determinar los que son relevantes. Una vez
que se determinan, se combinan para encontrar la solución óptima del problema
original.
Se sabe que los coeficientes son números combinatorios que se calculan para una fila
del triángulo, a partir de números de la fila superior, entre los que se encuentra
comprendido el número que se calcula.
© Universidad Internacional de La Rioja (UNIR)
1 𝑠𝑖 𝑘 = 0 ó 𝑘 = 𝑛
𝑛 𝑛−1 𝑛−1
( )={ ( )+( ) 𝑠𝑖 0 < 𝑘 < 𝑛
𝑘 𝑘−1 𝑘
0 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜
Nótese que para un número combinatorio cualquiera será necesario, calcular todos
los anteriores, calculándose algunos resultados varias veces. Por ejemplo, para
calcular numCombinatorio(6,4) se necesita calcular numCombinatorio(5,3) y
numCombinatorio(5,4), pero cada uno de ellos necesita calcular
numCombinatorio(4,3), que se calculará más de una vez. Su complejidad está en el
𝑛
orden de 𝛺 (𝑘 ). Se podría realizar un algoritmo más eficiente mediante el cálculo del
triángulo de Pascal con una tabla que se iría llenando línea por línea.
5.6. Heurísticas
Son procedimientos que pueden producir o no una buena solución para un problema,
© Universidad Internacional de La Rioja (UNIR)
es decir, son procedimientos que puede producir una solución óptima, pero que no
es la mejor o, incluso, no encuentra una solución.
Según Rego et al. (2011) «un método heurístico es un procedimiento para resolver
un problema de optimización bien definido mediante una aproximación intuitiva, en
la que la estructura del problema se utiliza de forma inteligente para obtener una
buena solución».
En el problema del viajante se cuenta con una serie de ciudades para las que se
conocen las distancias entre ellas. El viajante deberá salir de una de esas ciudades
y visitar todas las demás una vez, retornando al punto de partida y habiendo
recorrido la menor distancia posible. Se debe tener en cuenta, que encontrar los
métodos exactos para este problema necesitan un tiempo exponencial, por lo que no
son viables para un número grande de nodos.
En este caso, se trata del recorrido de un grafo del que se conoce el origen.
Se puede usar un grafo completo 𝐺 = (𝑉, 𝐸) no dirigido con tantos nodos en 𝑉 como
© Universidad Internacional de La Rioja (UNIR)
Existen varias formas de tratarlo mediante métodos heurísticos. Una de las más
habituales será la forma iterativa, usando un algoritmo voraz. En cada iteración del
La Figura 9 muestra el grafo de distancias entre seis ciudades. Se han numerado las
ciudades o vértices a partir de 0 para que se entienda mejor la implementación.
Tabla 5. Representación matricial del grafo del problema del viajante. Fuente: elaboración propia.
Por valor tocaría la {0,4}, pero no se selecciona porque no cumple ninguna de las
dos condiciones indicadas, ya que formaría un ciclo completo con las anteriores y
sería la tercera arista que llega al vértice 4.
El siguiente que sería el {1,4} que no cierra el ciclo, pero si fuera la tercera arista
que llega al 4, tampoco se coge.
El siguiente en valor {2,3} tampoco se selecciona por el mismo motivo que el
anterior, en este caso para el vértice 2.
El {0,2} no se selecciona porque no cumple ninguna de las dos condiciones y el
{0,3} cierra ciclo, así que tampoco se selecciona.
El {1,3} visitaría por tercera vez el vértice 1.
En este algoritmo se reorganizarían las aristas, que son simétricas, para mostrar el
camino enlazado, es decir, se muestra el ciclo correcto y se obtiene el siguiente orden
de aristas:
Figura 10. Código y ejecución de una heurística voraz para el problema del viajante. Fuente:
elaboración propia.
Rego, C., Gamboa, D., Glover, F. y Osterman, C. (2011). Traveling salesman problem
heuristics: Leading methods, implementations and latest advances. European Journal
of Operational Research, 211(3), pp. 427-441.
[Link]
© Universidad Internacional de La Rioja (UNIR)
Tabla 6. Estado de la lista en las distintas etapas del algoritmo. Fuente: elaboración propia.
Solución:
Figura 12. Implementación ejercicio 2. Búsqueda secuencial recursiva. Fuente: elaboración propia.
© Universidad Internacional de La Rioja (UNIR)
Solución:
Solución:
Esta es una de las soluciones más sencillas de este problema. Se supone que los
objetos pueden ser fraccionados. Básicamente se tiene 𝑛 objetos, que cuentan con
un peso y un valor. Se puede tomar una fracción de un objeto 𝑖. Se representa como
𝑓𝑜𝑏𝑗 𝑖
© Universidad Internacional de La Rioja (UNIR)
Se trata de maximizar
𝑛
∑ 𝑓_𝑜𝑏𝑗𝑖 𝑣𝑎𝑙𝑜𝑟𝑖
𝑖=1
Las opciones para llenar la mochila sería ir escogiendo los de más valor primero, los
de menor peso, para que la mochila se llene más despacio o los objetos cuyo valor
por unidad de peso sea mayor. Es precisamente este enfoque el que se va a
implementar, ya que asegura que la solución que se encuentra es óptima.
En este caso no se pueden fraccionar los objetos, por lo que la solución se complica
bastante. El objetivo y las restricciones son las mismas que en el ejercicio anterior.
Solución:
Para poderlo resolver, se usa una tabla con las filas representando los objetos y las
columnas, los pesos. La lista de objetos posibles se proporciona ordenada por pesos.
En este caso se ha incorporado la lista de objetos como atributo para poder rescatar
la información de estos, que se introducen en la mochila en cualquier momento.
© Universidad Internacional de La Rioja (UNIR)
Excepto 𝑡𝑎𝑏𝑙𝑎[0, 𝑗] = 0 𝑠𝑖 𝑗 ≥ 0.
En los casos en los que 𝑗 − 𝑝𝑒𝑠𝑜𝑖 < 0, se toma 𝑡𝑎𝑏𝑙𝑎[𝑖][𝑗] = 𝑉[𝑖 − 1, 𝑗].
En todo caso, en cada celda no puede haber valores de objetos pesen más a el
representado por la columna.
La tabla demuestra que existe una carga óptima con valor 27. A partir de la tabla se
pueden recuperar cuáles son los objetos introducidos.
Figura 16. Código ejercicio 5. Problema de la mochila con programación dinámica. Fuente:
elaboración propia.
© Universidad Internacional de La Rioja (UNIR)
Recurso en línea muy completo para indagar sobre algoritmos, su análisis y diseño,
además de su aplicación para la resolución de problemas
Uso de heurísticas
Fox, P. (s. f.) Usar heurísticas. Khan Academy. Usar heurísticas (artículo) | Algoritmos |
Khan Academy
Wextensibles ([Link]
8. En la programación dinámica:
A. Se divide el problema en subproblemas y se usa la recursividad para
solucionarlos.
© Universidad Internacional de La Rioja (UNIR)