# data[].attributes.body
El término Divide y Vencerás en su acepción más amplia es algo más que una técnica de diseño de algoritmos.
De hecho, suele ser considerada una filosofía general para resolver problemas y de aquí que su nombre no sólo forme parte del vocabulario informático, sino que también se utiliza en muchos otros ámbitos.
En nuestro contexto, Divide y Vencerás es una técnica de diseño de algoritmos que consiste en resolver un problema a partir de la solución de subproblemas del mismo tipo, pero de menor tamaño. Si los subproblemas son todavía relativamente grandes se aplicará de nuevo esta técnica hasta alcanzar subproblemas lo suficientemente pequeños para ser solucionados directamente. Ello naturalmente sugiere el uso de la recursión en las implementaciones de estos algoritmos.
La resolución de un problema mediante esta técnica consta fundamentalmente de los siguientes pasos:
1. En primer lugar ha de plantearse el problema de forma que pueda ser descompuesto en k subproblemas del mismo tipo, pero de menor tamaño. Es decir, si el tamaño de la entrada es n, hemos de conseguir dividir el problema en k subproblemas (donde 1 ≤ k ≤ n), cada uno con una entrada de tamaño nk y donde 0 ≤ nk < n. A esta tarea se le conoce como división.
2. En segundo lugar han de resolverse independientemente todos los subproblemas, bien directamente si son elementales o bien de forma recursiva. El hecho de que el tamaño de los subproblemas sea estrictamente menor que el tamaño original del problema nos garantiza la convergencia hacia los casos elementales, también denominados casos base.
3. Por último, combinar las soluciones obtenidas en el paso anterior para construir la solución del problema original.
otros ejemplos en los siguientes links:
http://www.dia.eui.upm.es/asignatu/alg_com/Transparencias/5%20-%20Divide%20y%20Vencer%C3%A1s.pdf
https://es.khanacademy.org/computing/computer-science/algorithms/merge-sort/a/divide-and-conquer-algorithms

# data[].attributes.body
Los algoritmos voraces, ávidos o de avance rápido (en inglés greedy) se utilizan normalmente en problemas de optimización.
El problema se interpreta como: “tomar algunos elementos de entre un conjunto de candidatos”.
El orden el que se cogen puede ser importante o no. Un algoritmo voraz funciona por pasos:
– Inicialmente partimos de una solución vacía.
– En cada paso se escoge el siguiente elemento para añadir a la solución, entre los candidatos.
– Una vez tomada esta decisión no se podrá deshacer.
– El algoritmo acabará cuando el conjunto de elementos seleccionados constituya una solución.
Ejemplo: “el viejo algoritmo de comprar patatas en el mercado”.
• Se puede generalizar el proceso intuitivo a un esquema algorítmico general.
• El esquema trabaja con los siguientes conjuntos de elementos:
– C: Conjunto de elementos candidatos, pendientes de seleccionar (inicialmente todos).
– S: Candidatos seleccionados para la solución.
– R: Candidatos seleccionados pero rechazados después.
• ¿Cuál o cuáles son los candidatos? Depende de cada problema.

# data[].attributes.body
La técnica de backtracking esta muy asociada a la recursividad, o mas propiamente, a la estructura recursiva de la mayoría de tipos de datos: listas, árboles, etc.

Esta técnica consiste básicamente en

Enumerar sistemáticamente las alternativas que existen en cada momento para dar con la solución a un problema.

Se prueba una alternativa, guardando memoria del resto de alternativas.

Si no damos con la solución, podemos dar marcha atrás (backtracking) y probar otra alternativa.

Para entender el concepto pongamos un ejemplo muy típico de la vida real. Supongamos que nos quedamos sin leche en la nevera y decidimos salir urgentemente a comprar un cartón de leche. Tenemos dos alternativas para solucionar el problema:

Ir a la tienda de la esquina.

Ir al supermercado.

Ahora probamos la alternativa 1.1, y nos vamos a la tienda de la esquina. Ops !! Me olvidé de que hoy es Domingo, así que la tienda esta cerrada. Afortunadamente, guardo memoria de otra alternativa, así que doy marcha atrás y elijo ir al supermercado. Como las Grandes Superficies siempre están abiertas, entro en el supermercado pero, ¿Dónde esta la leche?. Se plantean otras dos alternativas:

Ir al refrigerador de los yogures.

Ir al pasillo de alimentación.

Elijo la alternativa 2.1, pero en el refrigerador no hay leche. De nuevo, recuerdo la otra posibilidad, ir al pasillo de alimentación donde encuentro el cartón de leche. ¡ Problema resuelto !.

Esta técnica tan trivial resulta especialmente útil para los problemas de búsqueda en estructuras de datos. Especialmente si no existe a priori ningún criterio de búsqueda mejor o peor. El inconveniente es que hay que explorar sistemáticamente todas las alternativas, lo que resulta muy lento en general.

Como hemos visto, un algoritmo de backtracking tiene ciertos requerimientos:

Un espacio de búsqueda, esto es un conjunto de posibilidades o "estados" del problema a resolver. En general, un estado puede estar definido por el elemento de la estructura de datos que queremos tratar en cada instante. Por ejemplo, en un árbol, cada uno de sus nodos.

Un estado inicial, el punto de partida del problema.

Un conjunto de estados finales. Estos se definen mediante alguna característica, criterio o condición. Por ejemplo, todos los nodos de un árbol que almacenen un número entero igual a 10.

Una memoria de estados. Generalmente una pila donde guardamos los estados de búsqueda, es decir las alternativas posibles en cada momento.

# data[].attributes.attachment_link.title
Algorítmia - Tema 5. Backtracking. Mochila - Andrés Muñoz Ortega

# data[].attributes.body
La recursividad es un concepto fundamental en matemáticas y en computación.
Es una alternativa diferente para implementar estructuras de repetición (ciclos). Los módulos se hacen llamadas recursivas.
Se puede usar en toda situación en la cual la solución pueda ser expresada como una secuencia de movimientos, pasos o transformaciones gobernadas por un conjunto de reglas no ambiguas.
Las funciones recursivas se componen de:
Caso base: una solución simple para un caso particular (puede haber más de un caso base).
Caso recursivo: una solución que involucra volver a utilizar la función original, con parámetros que se acercan más al caso base. Los pasos que sigue el caso recursivo son los siguientes:
1. El procedimiento se llama a sí mismo
2. El problema se resuelve, tratando el mismo problema pero de tamaño menor
3. La manera en la cual el tamaño del problema disminuye asegura que el caso base eventualmente se alcanzará