Académique Documents
Professionnel Documents
Culture Documents
Ramificación y Poda
Pregrado
1. Antúnez Gonzales Valentín
2. Artica Villaroel José Luis
3. Aroni Carbajal Sergio
4. Arzapalo Caldas Cesar Kennedy Rousseau
5. Berrospi Farias Uzziel Moises
6. Cabrera Ticliahuanca Joel
Junio 2018
Índice
1. Introducción.
2. Heurística.
3. Métodos de optimización.
4. Backtrack.
7. Conclusiones
INTRODUCCIÓN
Este método de diseño de algoritmos es en realidad una variante del diseño Vuelta Atrás. Esta
técnica de diseño, cuyo nombre en castellano proviene del término inglés Branch and Bound,
se aplica normalmente para resolver problemas de optimización. Ramificación y Poda, al igual
que el diseño Vuelta Atrás, realiza una enumeración parcial del espacio de soluciones
basándose en la generación de un árbol de expansión.
La técnica de Ramificación y poda se suele interpretar como un árbol de soluciones, donde
cada rama nos lleva a una posible solución posterior a la actual. La característica de esta técnica
con respecto a otras anteriores (y a la que debe su nombre) es que el algoritmo se encarga de
detectar en qué ramificación las soluciones dadas ya no están siendo óptimas, para «podar»
esa rama del árbol y no continuar malgastando recursos y procesos en casos que se alejan de
la solución óptima.
Una característica que le hace diferente al diseño Vuelta Atrás es la posibilidad de generar
nodos siguiendo distintas estrategias. Recordemos que el diseño Vuelta Atrás realiza la
generación de descendientes de una manera sistemática y de la misma forma para todos los
problemas, haciendo un recorrido en profundidad del árbol que representa el espacio de
soluciones.
Terminología:
Nodo vivo: Nodo del espacio de soluciones del que no se han generado aún
todos sus hijos.
Búsqueda con retroceso: Tan pronto como se genera un nuevo hijo del nodo
en curso, este hijo pasa a ser el nodo en curso.
Ramificación y poda: Se generan todos los hijos del nodo en curso antes de
que cualquier otro nodo vivo pase a ser el nuevo nodo en curso.
heurística
En programación es vista como el arte de inventar por parte de los seres humanos,
con la intención de procurar estrategias, métodos, criterios, que permitan resolver
problemas a través de la creatividad.
Principios heurísticos:
Son los que establecen sugerencias para encontrar la solución idónea al
problema.
Reglas heurísticas:
Son las que señalan los medios para resolver el problema.
Estrategias heurísticas:
Son aquellas que permiten organizar los materiales o recursos compilados
que contribuyen a la búsqueda de la solución del problema.
Método heurístico
¿Qué es un método?
¿Qué es la optimización?
Programación Lineal:
Función Objetivo:
Este árbol es conceptual, en donde cada nodo de nivel k representa una parte de
la solución y está formado por k etapas que se suponen ya realizadas.
Sus hijos son las prolongaciones posibles al añadir una nueva etapa.
En este recorrido pueden suceder dos cosas, La primera es que tenga éxito si,
procediendo de esta manera, se llega a una solución (una hoja del árbol).
Por otra parte, el recorrido no tiene éxito si en alguna etapa la solución parcial
construida hasta el momento no se puede completar; entonces el nodo en el cual
nos encontramos se denomina nodos fracaso.
En este retroceso, si existe uno o más caminos aún no explorados que puedan
conducir a solución, el recorrido del árbol continúa por ellos.
Ramificación y poda
Definición:
El algoritmo de Ramificación y poda (conocido también como Ramificación y cota o ”Branch
and Bound” por su significado en inglés) es una manera de combinar el ahorro de espacio de
búsqueda en profundidad con información heurística.
Es particularmente aplicable cuando existen muchos caminos hacia un objetivo y se desea
una trayectoria óptima. La idea principal del algoritmo de búsqueda de Ramificacion y poda
es mantener el camino de costo más bajo hacia una meta encontrada demasiado lejos.
Supongamos que el costo es obligado. Si la búsqueda encuentra o arroja un camino tal que
costo (p) + h (p) ≥ que se estableció, el camino puede ser podado. Si un camino no podado
hacia la meta es encontrado, debe ser mejor que el camino más óptimo. Esta nueva solución
es almacenada y el costo establecido se coloca a esta nueva solución, así sucesivamente se
continua con la búsqueda hasta encontrar una nueva solución.
La búsqueda del Algoritmo de Branch and Bound genera una secuencia de mejores
soluciones. Una vez que se ha encontrado una solución, continua buscando una mejor. El
algo- ritmo de Branch and Bound es típicamente utilizado en búsquedas de profundidad. El
algoritmo recuerda el camino de menor costo encontrado y devuelve este camino cuando
finalice la búsqueda.
Nodos:
Nodo vivo: Aquel que no ha sido podado y que puede ser ramificado.
Nodo muerto: Nodo del que no se van a generar más hijos, porque:
o Se llega a una solución.
o No genera nuevas soluciones factibles.
o No genera mejores soluciones que la mejor conocida hasta el momento.
Estrategia 1
Si a partir de un nodo xi se puede obtener una solución válida, entonces se podrá podar dicho
nodo si la cota superior CS(xi) es menor o igual que la cota inferior CI(xj) para algún nodo j
generado en el árbol.
Por ejemplo: Supongamos el problema de la mochila, el cual se va a desarrollar en la sección
de ejemplos, donde utilizamos un árbol binario. Entonces:
Si a partir de xi se puede encontrar un beneficio máximo de CS(xi) = 4 y a partir de xj, se
tiene asegurado un beneficio mínimo de CI(xj) = 5, esto nos llevará a la conclusión de que se
puede podar el nodo xi sin que perdamos ninguna posible solución óptima.
Estrategia 2
Si se obtiene una posible solución válida para el problema con un beneficio Bj, entonces se
podrán podar aquellos nodos xi cuya cota superior CS(xi) sea menor o igual que el beneficio
que se puede obtener Bj (este proceso sería similar para la cota inferior).
Estrategias de Ramificación
Como se comenta en la introducción de éste apartado, la expansión del árbol con las distintas
estrategias está condicionada por la búsqueda de la solución óptima. Debido a esto todos los
nodos de un nivel deben ser expandidos antes de alcanzar un nuevo nivel, cosa que es lógica
ya que para poder elegir la rama del árbol que va a ser explorada, se deben conocer todas las
ramas posibles.
Todos estos nodos que se van generando y que no han sido explorados se almacenan en lo
que se denomina Lista de Nodos Vivos (a partir de ahora LNV), nodos pendientes de
expandir por el algoritmo.
La LNV contiene todos los nodos que han sido generados pero que no han sido explorados
todavía. Según como estén almacenados los nodos en la lista, el recorrido del árbol será de
uno u otro tipo, dando lugar a las tres estrategias que se detallan a continuación.
Estrategia FIFO
En la estrategia FIFO (First In First Out), la LNV será una cola, dando lugar a un recorrido
en anchura del árbol.
Estrategia LIFO
En la estrategia LIFO (Last In First Out), la LNV será una pila, produciendo un recorrido en
profundidad del árbol.
En la figura 2 se muestra el orden de generación de los nodos con una estrategia LIFO. El
proceso que se sigue en la LNV es similar al de la estrategia FIFO, pero en lugar de utilizar
una cola, se utiliza una pila.
Estrategia de Menor Coste o LC
Al utilizar las estrategias FIFO y LIFO se realiza lo que se denomina una búsqueda “a
ciegas”, ya que expanden sin tener en cuenta los beneficios que se pueden alcanzar desde
cada nodo. Si la expansión se realizase en función de los beneficios que cada nodo reporta
(con una “visión de futuro”), se podría conseguir en la mayoría de los casos una mejora
sustancial.
Es así como nace la estrategia de Menor Coste o LC (Least cost), selecciona para expandir
entre todos los nodos de la LNV aquel que tenga mayor beneficio (o menor coste). Por tanto,
ya no estamos hablando de un avance “a ciegas”.
Esto nos puede llevar a la situación de que varios nodos puedan ser expandidos al mismo
tiempo. De darse el caso, es necesario disponer de un mecanismo que solucione este
conflicto:
-Estrategia LC-FIFO: Elige de la LNV el nodo que tenga mayor beneficio y en caso de
empate se escoge el primero que se introdujo.
-Estrategia LC-LIFO: Elige de la LNV el nodo que tenga mayor beneficio y en caso de
empate se escoge el último que se introdujo.
Ramificación y Corte
Ramificación y corte es un método de optimización combinacional para resolver problemas
de enteros lineales, que son problemas de programación lineal donde algunas o todas las
incógnitas están restringidas a valores enteros. Se trata de un híbrido de ramificación y poda
con métodos de planos de corte.
Este método resuelve programas lineales sin restricciones enteras usando algoritmos
regulares simplificados. Cuando se obtiene una solución óptima que tiene un valor no entero
para una variable que ha de ser entera, el algoritmo de planos de corte se usa para encontrar
una restricción lineal más adelante que sea satisfecha por todos los puntos factibles enteros,
pero violados por la solución fraccional actual. Si se encuentra esa desigualdad, se añade al
programa lineal, de tal forma que resolverla nos llevará a una solución diferente que
esperamos que sea “menos fraccional”. Este proceso se repite hasta que ó bien, se encuentra
una solución entera (que podemos demostrar que es óptima), ó bien no se encuentran más
planos de corte.
En este punto comienza la parte del algoritmo de ramificación y poda. Este problema se
divide en dos versiones: una con restricción adicional en que la variable es más grande o
igual que el siguiente entero mayor que el resultado intermedio, y uno donde la variable es
menor o igual que el siguiente entero menor. De esta forma se introducen nuevas variables
en las bases de acuerdo al número de variables básicas que no son enteros en la solución
intermedia, pero son enteros de acuerdo a las restricciones originales. Los nuevos programas
lineales se resuelven usando un método simplificado y después el proceso repetido hasta que
una solución satisfaga todas las restricciones enteras.
Durante el proceso de ramificación y poda, los planos de corte se pueden separar más
adelante y pueden ser o cortes globales válidos para todas las soluciones enteras factibles, o
cortes locales que son satisfechos por todas las soluciones llenando todas las ramas de la
restricción del subárbol de ramificación y poda actual.
ESTRATEGIAS DE RAMIFICACIÓN:
ESTRATEGIA FIFO
Lista de nodos vivos: Cola FIFO.
Recorrido del árbol en anchura.
Ejemplo:
RECORRIDO EN ANCHURA
(Código java)
while(!q.empty())
{
State st = q.front();
q.pop();
if (st.node == nodo){
printf("'%d'n",nodo);
return;
}else printf("%d ",st.node);
int T = (int)graph.G[st.node].size();
for(int i = 0; i < T; ++i)
{
if (!mark[graph.G[st.node][i].node])
{
mark[graph.G[st.node][i].node] = true;
q.push(State(graph.G[st.node][i].node));
}
}}
PROBLEMA DE MINIMIZACION
(Algoritmo)
(C,s) BranchAndBoundMin (nodoRaíz)
{
LNV = {nodoRaíz};
(C,s) = CS(nodoRaíz); Greedy)
while (LNV ≠ ∅) {
x = seleccionar(LNV);
LNV = LNV - {x};
if ( CI(x) <= C )
foreach (y hijo de x)
if (y es una solución final mejor que s) {
s = y;
C = coste(y);
} else if ( y no es solución final
&& (CI(y) <= C) ) {
LNV = LNV + {y};
(Ctmp,Stmp) = CS (y);
if (Ctmp < C) { C = Ctmp; s = Stmp; }
}
} // del bucle while (LNV ≠ ∅)
return (C,s);}
PROBLEMA DE MAXIMIZACIÓN
(Algoritmo)
(C,s) BranchAndBoundMax (nodoRaíz)
{
LNV = {nodoRaíz};
(C,s) = CI(nodoRaíz); // Primera solución (p.ej. Greedy)
while (LNV ){
x = seleccionar(LNV); // Según un criterio FIFO,
LNV = LNV - {x};
if ( CS(x) >= C )
foreach (y hijo de x)
if (y es una solución final mejor que s) { s = y;
C = beneficio(y);
} else if ( y no es solución final
&& (CS(y) >= C) ) { LNV = LNV + {y};
(Ctmp,Stmp) = CI (y);
if (Ctmp > C) { C = Ctmp; s = Stmp; }
}
return (C,s);
}
CODIGO JAVA DE OPTIMIZACIÓN DE UN PROBLEMA
import java.util.*;
Optimizacionproblema[] subPs =
Ri.branch();
for(int k=0;k<subPs.length;k++){
this.activeproblems.addElement(subPs[k]);
this.nodesGenerated++; }}
}
}
Date d1 = new Date();
this.elapsedTime =
(double)(d1.getTime()-d0.getTime())/1000;
return soluc;
}
int dato;
dato = Elem;
if (Hizq == null)
else
Hizq.InsertaBinario(Elem);
else{
if (Hder == null)
else
Hder.InsertaBinario(Elem);
} } }}
class Arbol{
NodoBinario Padre;
NodoBinario Raiz;
public Arbol(){
Raiz = null;
if(Raiz == null)
else
Raiz.InsertaBinario (Elem);
if(Nodo == null)
return;
else{
Preorden (Nodo.Hizq);
Preorden (Nodo.Hder);
if(Nodo == null)
return;
else{
PostOrden (Nodo.Hizq);
PostOrden (Nodo.Hder);
if(Nodo == null)
return;
else{
Inorden (Nodo.Hizq);
Inorden (Nodo.Hder);
return;
else{
if(Elem>A.dato)
else
return Math.max(Altder,Altizq);
NodoBinario T = null;
if(Nodo != null){
cola.InsertaFinal (Nodo);
while(!(cola.VaciaLista ())){
T = cola.PrimerNodo.datos;
cola.EliminaInicio();
if (T.Hizq != null)
cola.InsertaFinal (T.Hizq);
if (T.Hder != null)
cola.InsertaFinal (T.Hder);
System.out.println();
class NodosListaA{
NodoBinario datos;
NodosListaA siguiente;
datos =valor;
datos = valor;
class Cola{
NodosListaA PrimerNodo;
NodosListaA UltimoNodo;
String Nombre;
public Cola(){
this ("Lista");
//Constructor
Nombre = s;
PrimerNodo = UltimoNodo =null;
if(VaciaLista())
else
if(VaciaLista())
else
//Eliminar al Inicio
if(VaciaLista())
if(PrimerNodo.equals (UltimoNodo))
else
PrimerNodo = PrimerNodo.siguiente;
//Elimina al final
if(VaciaLista())
if (PrimerNodo.equals (UltimoNodo))
else{
Actual = Actual.siguiente;
UltimoNodo =Actual;
Actual.siguiente = null;
class ArbolBinarioA{
A.InsertaNodo (10);
A.InsertaNodo (7);
A.InsertaNodo (8);
A.InsertaNodo (6);
A.InsertaNodo (12);
A.InsertaNodo (11);
A.InsertaNodo (5);
A.InsertaNodo (4);
A.InsertaNodo (3);
A.InsertaNodo (2);
A.Preorden (A.Raiz);
System.out.println();
A.Inorden (A.Raiz);
System.out.println();
A.PostOrden (A.Raiz);
System.out.println();
A.Anchura (A.Raiz);
Conclusiones:
• Ramificación y poda:
Mejora y generalización de la técnica de backtracking.
• Idea básica:
Recorrido implícito en árbol de soluciones:
- Distintas estrategias de ramificación.
- Estrategias LC: explorar primero las ramas más prometedoras.
- Poda basada en acotar el beneficio a partir de un nodo: CI, CS.
• Estimación de cotas:
Aspecto clave en RyP. Utilizar algoritmos de avance rápido.
• Compromiso tiempo-exactitud:
- Más tiempo => Mejores cotas.
- Menos tiempo => menos poda.
Bibliografía:
[1] Brassard G., Bratley P., Fundamentos de algoritmia. Prentice Hall, 1997.
[2] Aho A.V., Hopcroft J.E., Ullman J.D., Estructuras de datos y algoritmos.
Addison-Wesley, 1988.
[3] Sartaj Sahni, Data Structures, Algoriths, and Applications in Java. Mc Graw
Hill, 2000 El capítulo sobre Ramificación y Poda está en la web:
http://www.cise.ufl.edu/~sahni/dsaaj/