Problema de La Mochila
Problema de La Mochila
Problema de La Mochila
(KNAPSACK PROBLEM)
1. INTRODUCCIN
El problema de la mochila es un problema simple de entender: hay una
persona que tiene una mochila con una cierta capacidad y tiene que elegir qu
elementos pondr en ella. Cada uno de los elementos tiene un peso y aporta
un benecio. El objetivo de la persona es elegir los elementos que le permitan
maximizar el benecio sin excederse de la capacidad permitida.
A la vez es un problema complejo, si por complejidad nos referimos a la
computacional. Un problema se cataloga como inherentemente difcil si su
solucin requiere de una cantidad signicativa de recursos computacionales,
sin importar el algoritmo utilizado. El problema de la mochila forma parte de
una lista histrica de problemas NP Completos elaborada por Richard Karp
en 1972.
En el caso del problema de la mochila, si contramos con 4 productos, para
saber cul es la mejor solucin podramos probar las 2
4
= 16 posibilidades. El
2 se desprende del hecho de que cada decisin es incluir o no al producto y el
4 de la cantidad de productos. 16 posibilidades es un nmero manejable, sin
embargo, si la cantidad de elementos por ejemplo ascendiera a 20, tendramos
que analizar nada ms y nada menos que 2
20
= 1,048,576 posibilidades.
2. DEFINICIN FORMAL DEL PROBLEMA
Supongamos que tenemos n distintos tipos de tems, que van del 1 al n. De
cada tipo de tem se tienen q
i
tems disponibles, donde q
i
es un entero positivo
que cumple:
Cada tipo de tem i tiene un beneficio asociado dado por v
i
y un peso (o
volumen) w
i
. Usualmente se asume que el beneficio y el peso no son
negativos. Para simplificar la representacin, se suele asumir que los tems
estn listados en orden creciente segn el peso (o volumen).
Por otro lado se tiene una mochila, donde se pueden introducir los tems, que
soporta un peso mximo (o volumen mximo) W.
El problema consiste en meter en la mochila tems de tal forma que
se maximice el valor de los tems que contiene y siempre que no se
supere el peso mximo que puede soportar la misma. La solucin al
problema vendr dado por la secuencia de variables x
1
, x
2
, ..., x
n
donde el
valor de x
i
indica cuantas copias se metern en la mochila del tipo de tem i.
El problema se puede expresar matemticamente por medio del
siguiente programa lineal:
Maximizar
Tal que
Si
El Quicksort trabaja particionando el conjunto a ordenar en dos partes, para
despus ordenar dichas partes independientemente. El punto clave del
algoritmo est en el procedimiento que divide el conjunto. El proceso de
divisin del conjunto debe cumplir las siguientes tres condiciones:
a. El elemento pivote=a[i] est en su posicin final en el array para algn
ndice i.
b. Todos los elementos en a[first], ..., a[i-1] son menores o iguales a a[i].
c. Todos los elementos en a[i+1], ..., a[last] son mayores que a[i].
En este punto se aplica el mismo mtodo recursivamente a los dos
subproblemas generados: a[first], ... , a[i-1] y a[i+1], ... , a[last]. El resultado
final ser una matriz completamente ordenada, y por tanto no hace falta un
paso subsiguiente de combinacin.
4. EL ALGORITMO
A. ANLISIS DEL PROBLEMA
Para el anlisis tomaremos un caso en particular.
Sea el conjunto de elementos (6) con las siguientes caractersticas:
0 1 2 3 4 5
VALOR 50 40 30 66 20 60
PESO 60 40 20 30 10 50
Y una mochila con capacidad de 100.
a. VORAZ SIN ORDENAMIENTO
Si tomamos los elementos tal cual son ingresados (sin ordenamiento
previo). Tomaramos los 2 primeros:
VALOR PESO FRACCIN
50 60 1
40 40 1
Valor mximo obtenido: 90
b. MAYOR VALOR
Si consideramos como parmetro de decisin el valor de los objetos a
escoger, tomaramos los siguientes elementos:
VALOR PESO FRACCIN
66 30 1
60 50 1
50 60 1/3
Para el caso de MOCHILA FRACCIONARIA debemos tomar solo una
porcin del ltimo elemento para no excedernos en el peso.
Valor mximo obtenido: 142.667
VALOR PESO
66 30
Para el caso de MOCHILA NO FRACCIONARIA tomamos el siguiente
elemento con mayor valor cuyo peso sea menor o igual al peso
restante antes de sobrepasar la capacidad de la mochila.
Valor mximo obtenido: 156
Observamos mejores resultados respecto del caso anterior.
c. MENOR PESO
Si consideramos como parmetro de decisin el menor peso de los
objetos a escoger, tendramos la siguiente solucin
VALOR PESO FRACCIN
20 10 1
30 20 1
66 30 1
40 40 1
Valor mximo obtenido: 156
Observamos mejores resultados respecto del caso anterior.
d. MEJOR RENTABILIDAD
Concluimos que si tomamos en cuenta algn parmetro de ordenacin
previa de los vectores PESO y VALOR obtenemos mejores soluciones
para el problema. Sin embargo, an podemos optimizar la solucin si
consideramos los dos parmetros a la vez. Cmo? Relacionndolos.
Cmo los relacionamos? Con un nuevo parmetro al que llamaremos:
RENTABILIDAD, que viene a ser la relacin inversa entre VALOR y
PESO.
60 50
30 20
De esta manera generamos un nuevo vector RENTA a partir de los 2
iniciales:
0 1 2 3 4 5
VALOR 50 40 30 66 20 60
PESO 60 40 20 30 10 50
RENTA 0.83 1 1.5 2.2 2 1.2
Para el caso de MOCHILA FRACCIONARIA tomaremos los elementos
siguientes:
RENTA VALOR PESO FRACCIN
2.2 66 30 1
2 20 10 1
1.5 30 20 1
1.2 60 50 4/5
Valor mximo obtenido: 164
Para el caso de MOCHILA NO FRACCIONARIA tomaremos los
elementos siguientes:
RENTA VALOR PESO
2.2 66 30
2 20 10
1.5 30 20
1 40 40
Valor mximo obtenido: 156
B. IMPLEMENTACIN DEL ALGORITMO
a. ORDENAMIENTO
Realizamos el ordenamiento mediante el algoritmo de ordenamiento
Quicksort basado en el paradigma DnC (Divide y Conquer).
void quicksort(float v[], float w[],int inf,int sup)
{ int i,j,div; double pivote, tmp, tmp2, a, b;
div=(inf+sup)/2;
pivote=v[div]/w[div];
i=inf; j=sup;
do
{ while((v[i]/w[i])>pivote)i++;
while((v[j]/w[j])<pivote)j--;
if(i<=j)
{ tmp=v[j];
tmp2=w[j];
v[j]=v[i];
w[j]=w[i];
v[i]=tmp;
w[i]=tmp2;
i++; j--;
}
}while(i<=j);
if(inf<j) quicksort(v,w,inf,j);
if(i<sup) quicksort(v,w,i,sup);
}
b. SELECCIN DE ELEMENTOS
Implementamos un algoritmo simple para generar la solucin con los
vectores ya ordenados
Para el caso de MOCHILA FRACCIONARIA:
while(peso<capacidad&&i<n)
{ if(peso+w[i]<=capacidad)
solucion[i]=1;
else
solucion[i]=(capacidad-peso)/w[i];
peso=peso+w[i]*solucion[i];
i++;
}
Para el caso de MOCHILA NO FRACCIONARIA:
while(peso<capacidad&&i<n)
{ if(peso+w[i]<=capacidad)
solucion[i]=1;
peso=peso+w[i]*solucion[i];
i++;
}
ALGORITMO FINAL:
#include<conio.h>
#include<iostream>
using namespace std;
int n;
void quicksort(float v[], float w[],int inf,int sup)
{ int i,j,div; double pivote, tmp, tmp2;
div=(inf+sup)/2;
pivote=v[div]/w[div];
i=inf; j=sup;
do
{ while((v[i]/w[i])>pivote)i++;
while((v[j]/w[j])<pivote)j--;
if(i<=j)
{ tmp=v[j];
tmp2=w[j];
v[j]=v[i];
w[j]=w[i];
v[i]=tmp;
w[i]=tmp2;
i++; j--;
}
}while(i<=j);
if(inf<j) quicksort(v,w,inf,j);
if(i<sup) quicksort(v,w,i,sup);
}
/*---------------------------------------------------------*/
int main ()
{ int i, j;
float peso=0, valor=0, suma=0, capacidad;
system("color 0B");
cout<<"\n\n ---------------------[ KNAPSACK PROBLEM ]----------------------
";
cout<<"\n Divide and Conquer\n\n";
cout<<"\n\t CAPACIDAD DE LA MOCHILA: ";cin>>capacidad;
cout<<"\n\t CANTIDAD DE OBJETOS: ";cin>>n;
float w[n], v[n], solucion[n];
cout<<endl;
for(i=0;i<n;i++)
{ cout<<"\n\t Valor del objeto "<<i+1<<": "; cin>>v[i];
cout<<"\t Peso del objeto "<<i+1<<": "; cin>>w[i]; suma=suma+w[i];
}
if(suma>=capacidad)
{ for(i=0;i<n;i++)
solucion[i]=0;
quicksort(v,w,0,n-1);
i=0;
while(peso<capacidad&&i<n)
{ if(peso+w[i]<=capacidad)
solucion[i]=1;
else
solucion[i]=(capacidad-peso)/w[i];
peso=peso+w[i]*solucion[i];
i++;
}
system("cls");
cout<<"\n\n ---------------------[ MOCHILA FRACCIONARIA ]-----------------
-----\n";
cout<<"\n\tRENTA\tPESO\tVALOR\tFRACCION PESO EN MOCHILA\n\n";
for(i=0;i<n;i++)
if(solucion[i])
{ cout<<"\t "<<v[i]/w[i]<<"\t "<<w[i]<<"\t "<<v[i]<<"\t
"<<solucion[i]<<"\t\t "<<w[i]*solucion[i]<<endl;
valor=valor+v[i]*solucion[i];
}
cout<<"\n\t\t\t\t VALOR LOGRADO: "<<valor;
/* mochila no fraccionaria*/
for(i=0;i<n;i++)
solucion[i]=0;
i=0; peso=0; valor=0;
while(peso<capacidad&&i<n)
{ if(peso+w[i]<=capacidad)
solucion[i]=1;
peso=peso+w[i]*solucion[i];
i++;
}
cout<<"\n\n\n\n ---------------------[ MOCHILA NO FRACCIONARIA ]------------
----------\n";
cout<<"\n\tRENTA\tPESO\tVALOR\tFRACCION PESO EN MOCHILA\n\n";
for(i=0;i<n;i++)
if(solucion[i])
{ cout<<"\t "<<v[i]/w[i]<<"\t "<<w[i]<<"\t "<<v[i]<<"\t
"<<solucion[i]<<"\t\t "<<w[i]*solucion[i]<<endl;
valor=valor+v[i]*solucion[i];
}
cout<<"\n\t\t\t\t VALOR LOGRADO: "<<valor;
}
else cout<<"\n\n SOUCION TRIVIAL...";
getch();
return 0;
}
5. COMPLEJIDAD
En nuestro algoritmo la funcin del tiempo de ejecucin estara dada por el
algoritmo de ordenacin (Quicksort) y el de seleccin de los elementos.
Como sabemos la complejidad de un Quicksort es () y por simple
inspeccin obtenemos la complejidad del algoritmo de seleccin igual a ().
Entonces la funcin T.E. sera la siguiente:
() () ()
Para efecto de simplificacin la complejidad de nuestro algoritmo sera ()