Está en la página 1de 24

Informe de Matemática Discreta

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.

5. Ramificación y poda [Branch and Bounds]

5.1. Estrategias de Ramificación.

5.1.1. Tipos de Nodos.

5.2. Estrategias de Poda.

5.2.1. LIFO & FIFO.

6. Ejemplo del método en código JAVA.

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.

Ejemplo de árbol creado bajo la técnica de programación de ramificación y poda.


CARACTERÍSTICAS

 Al igual que los métodos de búsqueda con retroceso:

 Se aplica a problemas de optimización con restricciones.

 Se genera el espacio de soluciones, organizándolo en un árbol (en general en


un grafo).

 No se genera el espacio de soluciones completo, sino que se podan bastantes


estados.

 Terminología:

 Nodo vivo: Nodo del espacio de soluciones del que no se han generado aún
todos sus hijos.

 Nodo muerto: Nodo del que no se van a generar más hijos.

 Nodo en curso (o en expansión): Nodo del que se están generando hijos.

 Diferencia fundamental con el método de búsqueda con retroceso:

 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

La heurística se basa en la experiencia propia del individuo, y en la de otros para


encontrar la solución más viable al problema.

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.

Ahora bien, la heurística como disciplina científica, es aplicada con la finalidad


de elaborar medios, principios, reglas o estrategias como ayuda para lograr
encontrar la solución más eficaz y eficiente al problema que analiza el individuo.

Existen varios procedimientos heurísticos que se dividen en:

 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

Es el conjunto de métodos y técnicas que se emplean con el fin de encontrar y


solucionar un problema en aquellos casos que es difícil hallar una solución óptima o
satisfactoria.

El Matemático George Polya, en su libro “Cómo resolverlo”, en el cual explica el


método heurístico citando cuatro ejemplos:

 Si no consigues entender un problema, dibuja un esquema.


 Si no encuentras la solución, haz como si ya la tuvieras y mira qué puedes
deducir de ella (razonando a la inversa).
 Si el problema es abstracto, prueba examinar un ejemplo concreto.
 Intenta abordar primero un problema más general y revisar.
Métodos de optimización

Como el concepto de métodos de optimización es muy amplio, en nuestro


ámbito de estudio se dará un enfoque especifico con respecto a los algoritmos
de búsqueda de soluciones, teniendo en cuenta ello se citará definiciones
teniendo en cuenta lo anterior.

¿Qué es un método?

Método es un conjunto de operaciones ordenados y definidas para lograr un


fin determinado modo en que se obra algo con un determinado orden.

¿Qué es la optimización?

Método para determinar los valores de las variables que intervienen en un


proceso o sistema para que el resultado sea el mejor posible.

También consiste en maximizar o minimizar una función real.

Programación Lineal:

La programación lineal es el campo de la optimización matemática dedicado


a maximizar o minimizar (optimizar) una función lineal, denominada función
objetivo.

Función Objetivo:

La función objetivo es la ecuación que será optimizada dadas las limitaciones


o restricciones determinadas y con variables que necesitan ser minimizadas o
maximizadas usando técnicas de programación lineal o no lineal.
Backtracking

Backtracking o Vuelta Atrás es un algoritmo de búsqueda que generar todas las


posibles soluciones siempre que dichas soluciones sean susceptibles de resolverse
en etapas.

Backtracking se asemeja a un recorrido en profundidad dentro de un árbol cuya


existencia sólo es implícita.

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.

Para examinar el conjunto de posibles soluciones es suficiente recorrer este árbol


construyendo soluciones parciales a medida que se avanza en el recorrido.

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).

Si lo único que buscábamos era una solución al problema, el algoritmo finaliza


aquí; ahora bien, si lo que buscábamos eran todas las soluciones o la mejor de
entre todas ellas, el algoritmo seguirá explorando el árbol en búsqueda de
soluciones alternativas.

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 tal caso, el algoritmo vuelve atrás (“Y de ahí su nombre”) en su recorrido


eliminando los elementos que se hubieran añadido en cada etapa a partir de ese
nodo.

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.

 Nodo en curso (o en expansión): Aquel que se selecciona para ramificarlo.


Estrategias de Poda
Nuestro objetivo principal será eliminar aquellos nodos que no lleven a soluciones buenas.
Podemos utilizar dos estrategias básicas. Supongamos un problema de maximización donde
se han recorrido varios nodos i=1,…,n. estimando para cada uno la cota superior CS(xi) e
inferior CI(xi).

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.

En la figura 1 se puede observar que se comienza introduciendo en la LNV el nodo A.


Sacamos el nodo de la cola y se expande generando los nodos B y C que son introducidos en
la LNV. Seguidamente se saca el primer nodo que es el B y se vuelve a expandir generando
los nodos D y E que se introducen en la LNV. Este proceso se repite mientras que quede
algún elemento en la cola.

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 Poda "Relajado"


Una variante del método de ramificación y poda más eficiente se puede obtener “relajando”
el problema, es decir, eliminando algunas de las restricciones para hacerlo más permisivo.
Cualquier solución válida del problema original será solución válida para el problema
“relajado”, pero no tiene por qué ocurrir, al contrario. Si conseguimos resolver esta versión
del problema de forma óptima, entonces si la solución obtenida es válida para el problema
original, esto querrá decir que es óptima también para dicho problema.
La verdadera utilidad de este proceso reside en la utilización de un método eficiente que nos
resuelva el problema relajado. Uno de los métodos más conocidos es el de Ramificación y
Corte (Branch and Cut (versión inglesa)).

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.*;

public class BnB {


private Optimizacionproblema P;
private double U;
private Optimizacionproblema corr=null;
private Vector activeproblems;
static double M = Double.MAX_VALUE/1000;
private long nodesGenerated = 0;
private double elapsedTime = 0;
private OptimizacionProblemaComparcion opc;
private Optimizacionproblema soluc;
public BnB(Optimizacionproblema problem){
this.P = problem;
int n = P.getTamañoproblema();
activeproblems = new Vector(n*n,n);
activeproblems.addElement(P);
U = M;
this.opc = new OptimizacionProblemaComparcion();
}
public Optimizacionproblema solve(){
Optimizacionproblema Pi;
Optimizacionproblema Ri;
double Li;
Date d0 = new Date();
while(activeproblems.size()>0){
Pi = selectProblem();
Ri = Pi.getRelaxation();
Li = Ri.getValue();
if(Li<U){
if( P.isValid()){
U = Li;
this.soluc = Ri;
} else {
Ri.performUpperBounding(U);

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;
}

private Optimizacionproblema selectProblem(){


Optimizacionproblema selected;

//Sort the vector by the value


VectorSort.sort(this.activeproblems, opc);

//Select the best element and remove it from the list


selected =
(Optimizacionproblema)this.activeproblems.lastElement();
this.activeproblems.removeElementAt(this.activeproblems.size
()-1);
return selected;
} // of selectProblem()
public double getElapsedTime(){
return this.elapsedTime;
}

public long getNodeCount(){


return this.nodesGenerated}
}

CODIGO DE ARBOL EN JAVA


(Todas las funciones)
class NodoBinario{

int dato;

NodoBinario Hizq, Hder;

NodoBinario (int Elem){

dato = Elem;

NodoBinario Hizq, Hder = null;

public void InsertaBinario (int Elem){

if(Elem < dato){

if (Hizq == null)

Hizq = new NodoBinario(Elem);

else

Hizq.InsertaBinario(Elem);

else{

if (Elem > dato){

if (Hder == null)

Hder = new NodoBinario (Elem);

else

Hder.InsertaBinario(Elem);

} } }}
class Arbol{

Cola Cola = new Cola();

NodoBinario Padre;

NodoBinario Raiz;

public Arbol(){

Raiz = null;

public void InsertaNodo(int Elem){

if(Raiz == null)

Raiz = new NodoBinario (Elem);

else

Raiz.InsertaBinario (Elem);

public void Preorden (NodoBinario Nodo){

if(Nodo == null)

return;

else{

System.out.print (Nodo.dato + " ");

Preorden (Nodo.Hizq);

Preorden (Nodo.Hder);

public void PostOrden (NodoBinario Nodo){

if(Nodo == null)

return;

else{

PostOrden (Nodo.Hizq);

PostOrden (Nodo.Hder);

System.out.print (Nodo.dato + " ");

public void Inorden (NodoBinario Nodo){

if(Nodo == null)

return;
else{

Inorden (Nodo.Hizq);

System.out.print(Nodo.dato + " ");

Inorden (Nodo.Hder);

void Busqueda (int Elem, NodoBinario A){

if((A == null) | (A.dato == Elem)){

System.out.print(A.dato + " ");

return;

else{

if(Elem>A.dato)

Busqueda (Elem, A.Hder);

else

Busqueda ( Elem, A.Hizq);

public int Altura (NodoBinario Nodo){

int Altder = (Nodo.Hder == null? 0:1 + Altura (Nodo.Hder));

int Altizq = (Nodo.Hizq == null? 0:1 + Altura (Nodo.Hizq));

return Math.max(Altder,Altizq);

public void Anchura (NodoBinario Nodo){

Cola cola= new Cola();

NodoBinario T = null;

System.out.print ("El recorrido en Anchura es: ");

if(Nodo != null){

cola.InsertaFinal (Nodo);

while(!(cola.VaciaLista ())){

T = cola.PrimerNodo.datos;

cola.EliminaInicio();

System.out.print(T.dato + " ");

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;

//Construtor Crea un nodo del tipo Object

NodosListaA (NodoBinario valor){

datos =valor;

siguiente = null; //siguiente con valor de nulo

// Constructor Crea un nodo del Tipo Object y al siguiente nodo de la lista

NodosListaA (NodoBinario valor, NodosListaA signodo){

datos = valor;

siguiente = signodo; //siguiente se refiere al siguiente nodo

//Definición de la Clase Lista

class Cola{

NodosListaA PrimerNodo;

NodosListaA UltimoNodo;

String Nombre;

//Constructor construye una lista vacia con un nombre de List

public Cola(){

this ("Lista");

//Constructor

public Cola (String s){

Nombre = s;
PrimerNodo = UltimoNodo =null;

//Retorna True si Lista Vacía

public boolean VaciaLista() {

return PrimerNodo == null;

//Inserta un Elemento al Frente de la Lista

public void InsertaInicio (NodoBinario ElemInser){

if(VaciaLista())

PrimerNodo = UltimoNodo = new NodosListaA (ElemInser);

else

PrimerNodo = new NodosListaA (ElemInser, PrimerNodo);

//Inserta al Final de la Lista

public void InsertaFinal(NodoBinario ElemInser){

if(VaciaLista())

PrimerNodo = UltimoNodo = new NodosListaA (ElemInser);

else

UltimoNodo=UltimoNodo.siguiente =new NodosListaA (ElemInser);

//Eliminar al Inicio

public void EliminaInicio(){

if(VaciaLista())

System.out.println ("No hay elementos");

// Restablecer las referencias de PrimerNodo y UltimoNodo

if(PrimerNodo.equals (UltimoNodo))

PrimerNodo = UltimoNodo = null;

else

PrimerNodo = PrimerNodo.siguiente;

//Elimina al final

public void EliminaFinal (){

if(VaciaLista())

System.out.println ("No hay elementos");


// Restablecer las referencias de PrimerNodo y UltimoNodo

if (PrimerNodo.equals (UltimoNodo))

PrimerNodo = UltimoNodo = null;

else{

NodosListaA Actual =PrimerNodo;

while (Actual.siguiente != UltimoNodo)

Actual = Actual.siguiente;

UltimoNodo =Actual;

Actual.siguiente = null;

class ArbolBinarioA{

public static void main (String[]args){

Arbol A = new Arbol();

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);

System.out.print("El recorrido en Preorden es: ");

A.Preorden (A.Raiz);

System.out.println();

System.out.print("El recorrido en Inorden es: ");

A.Inorden (A.Raiz);

System.out.println();

System.out.print("El recorrido en Postorden es: ");

A.PostOrden (A.Raiz);
System.out.println();

System.out.println("La altura del arbol es: " + A.Altura (A.Raiz));

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/