0% encontró este documento útil (0 votos)
19 vistas14 páginas

Prade Act 22

Este documento explica el algoritmo de la mochila fraccional, incluyendo su complejidad temporal y espacial, la función de selección utilizada y su optimalidad, y otros métodos para resolver el problema como programación dinámica y ramificación y poda.

Cargado por

santiha97
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
19 vistas14 páginas

Prade Act 22

Este documento explica el algoritmo de la mochila fraccional, incluyendo su complejidad temporal y espacial, la función de selección utilizada y su optimalidad, y otros métodos para resolver el problema como programación dinámica y ramificación y poda.

Cargado por

santiha97
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 14

PROGRAMACIÓN Y

ESTRUCTURAS DE DATOS
AVANZADAS

Práctica 1 - Mochila fraccional


UNED Curso 2022 - 2023

ÍNDICE

Theory demonstration 3
Ejemplos de ejecución 7

Memoria de práctica 1
Código fuente 9

Memoria de práctica 2
Theory demonstration

1) Indica y razona sobre el coste temporal y espacial del algoritmo.


The temporal cost of the algorithm in most cases is O(n log n), where "n" is the number
of objects, because it requires iterating over the objects that are put into the backpack, in ad-
dition to having to sort them beforehand. A more detailed justification would be: The cost of
sorting is O(n log n) because "quicksort" is used, which follows a design based on recurrence,
following a "divide and conquer" strategy that ensures its complexity is O(log n). Since a
comparison is made for sorting, in the worst case, all elements are compared, raising the cost
to O(n log n). The cost of iterating over the sorted elements is O(n), being a simple iteration
over the number of objects in the problem. Knowing this, the total complexity ends up being
O(n log n) + O(n) = O(n log n).

The spatial cost is O(n) since the elements passed to the problem must be stored. A list
has been chosen to store the objects over which subsequent iterations are made both for sort-
ing and for selecting the objects.

2) Explica en qué consiste la función de selección utilizada y demuestra su


optimalidad.
La función seleccionada consiste en escoger el objeto cuyo valor por unidad de peso sea
el mayor de los que no están en la mochila. De esta manera aseguramos obtener siempre el
máximo beneficio posible, gracias a que se pueden fraccionar los objetos y así conseguimos
llenar la mochila siempre. Este es el único criterio de selección que consigue siempre la
solución óptima con el algoritmo voraz.

La explicación matemática se basa en suponer que hay una solución factible cualquiera
del problema: Y =( y 1 , y 2 , . .. , y n ) que se compara con la solución del algoritmo voraz:
X =( x 1 , x 2 , .. . , xn ). Si demostramos que el valor de la solución X: V ( X) es mayor o igual que
el valor de la solución Y: V (Y ), se deduce que X es óptima. Entendemos lo siguiente:

• Si todos los elementos x =1 la solución es óptima, en caso contrario, j es el menor índice


i

tal que x j <1. Esto significa que metemos los objetos enteros hasta llegar a uno que

Memoria de práctica 3
tenemos que fraccionar, 0< x j< 1, para no pasarnos del límite de la mochila. Lo cual a su vez
implica que no se podrá introducir más objetos después del fraccionado, x i=0 para i> j .

• Como Y es una solución factible, el peso total debe ser menor o igual al límite, por tanto:
n
∑ ( x i− y i) vi ≥ 0; Sea:
i=1

n n vi
V ( X)−V (Y )= ∑ (x i− y i)v i = ∑ (x i− y i) p i
i=1 i=1 pi
Consideramos que, mientras los objetos hayan sido ordenados de forma descendiente en
relación a su valor por unidad de peso, para índices i menores que j las fracciones escogidas
de los objetos en la solución X serán mayores o iguales a las escogidas en la solución Y, que
expresamos: x i− y i ≥0 ; para índices i mayores que j se produce el caso opuesto: x i− y i ≤0 . En
todos los casos (x i− y i )(v i / pi )≥(x i− y i)(v j / p j ) por lo que:
n v j vi n
V ( X)−V (Y )≥ ∑ (x i− y i) pi = ∑ (x − y ) p
i=1 p j pi i=1 i i i
Como los valores y pesos de los objetos son positivos, el valor por unidad de peso es
positivo, quedando así:
n n n
V ( X)−V (Y )≥ ∑ ( x i− y i) pi= ∑ x i p i− ∑ y i pi
i=1 i=1 i=1

Como dijimos antes, el peso total en la mochila de la solución Y es menor que el límite y
en la solución X el peso total es exactamente igual al límite por tanto:
n n
∑ x i p i− ∑ y i p i ≥ 0
i=1 i=1

De esta manera demostramos que ninguna solución factible tiene un valor mayor que el
de la solución X y por tanto X es una solución óptima.

3) Explica qué otros esquemas pueden resolver el problema y razona sobre su


idoneidad.
Otros esquemas comunes para resolver el problema consisten en usar programación
dinámica o ramificación y poda.

• La solución del problema usando programación dinámica se consigue reduciendo el


problema en subproblemas y construir la solución al problema original con las soluciones
de estos. En el caso de la mochila fraccional este método de buscar la solución se vuelve

Memoria de práctica 4
más complejo que en la versión del problema donde se eligen los objetos enteros; que
requiere construir una tabla donde las columnas van desde 0 hasta el peso máximo de la
mochila, y en las filas representamos los objetos. Se busca la solución siguiendo:

V(item, Capacity) = max{V(Previous(item), Capacity), ValueOf(item)


+ V(Previous(item), Capacity - WeightOf(item))}

La fórmula define una recursión donde se va eligiendo el máximo entre escoger el


elemento actual o no hacerlo, pero cada vez que se calcula V() guardamos ese resultado en
la tabla, de esa manera si hay que calcular un valor con una combinación que ya se ha
visitado, se saca de la tabla en vez de volver a calcularlo.
Pero cuando se aplica este método al problema de la mochila fraccional, se tiene que
añadir una variable a la fórmula en el camino cuando se selecciona el objeto. Esta variable
simboliza la fracción del objeto que se toma, quedaría la función como:

max{V(Previous(item), Capacity), ValueOf(item) + V(Previous(item),


Capacity - WeightOf(item * frac))}

La complejidad temporal y espacial de este método es de O(n * W) donde “n” es el


número de objetos y “W” es el peso máximo de la mochila, porque tenemos que crear una
tabla que guarde los valores de esas dimensiones. Por eso para el problema de la mochila
fraccional es mejor usar la implementación del algoritmo voráz frente a la programación
dinámica.

• El método de ramificación y poda consiste en tener un árbol con las posibles soluciones al
problema, recogiendo soluciones parciales y eliminando aquellas que no satisfacen los
criterios. Al igual que el método de programación dinámica, se recorre un árbol de
posibles combinaciones de objetos, la diferencia está en que en este método se eliminan las
ramas que no cumplen con unas cotas decididas además de aquellas que no son posibles.
La poda se consigue cuando el algoritmo evalúa el nodo de la rama actual y comprueba
que no cumple con las cotas, por tanto “poda” o deja de recorrer esa rama.

Primero hay que decidir una heurística a seguir para solucionar el problema, en base a la
cual se definen la cota superior en inferior. En el caso del problema planteado, se utiliza
como heurística la búsqueda del objeto con mayor valor por unidad de peso, las cotas se
definen al principio (por ejemplo cota inferior a 0 y superior a la suma de todos los

Memoria de práctica 5
valores) y por cada nodo del árbol que se evalúa comprobamos que aporte una solución
mejor que la cota inferior, se actualiza su valor y se comprueba que no supere la cota
superior. El algoritmo irá recorriendo las ramas que apunten a una solución óptima y
llegará a una solución recorriendo un número reducido de ramas.

Rápidamente vemos que este método no es óptimo, siendo el uso más común en el caso
del problema de la mochila con objetos indivisibles, dado que el método de ramificación y
poda sólo se plantea cuando no hay una solución posible con el algoritmo voraz.

Ejemplos de ejecución

Para los siguientes datos de entrada:

• nº de objetos -> 10
• Objetos (peso, valor) -> { (1, 5), (3, 7), (4, 6), (2, 4), (4, 5), (3, 2), (1, 4), (2, 5), (3, 5), (4,
7) }

• Peso máximo de la mochila -> 8


Obtenemos el siguiente resultado:

1 1.0 5.0 Podemos ver que alcanza la solución óptima


1 1.0 4.0 escogiendo los objetos de mayor valor por unidad de
2 1.0 5.0 peso, los objetos (1, 5), (1, 4), (2, 5), (3, 7), (2, 4); del
3 1.0 7.0 último solo puede escoger la mitad dado que no cabe
2 0.5 2.0 entero. Se consigue un valor total de 23.
23.0

Para los siguientes datos de entrada:

• nº de objetos -> 5

Memoria de práctica 6
• Objetos (peso, valor) -> { (1000, 200), (2000, 600), (3000, 900), (1500, 300), (2500, 500)
}

• Peso máximo de la mochila -> 6000


Obtenemos el siguiente resultado:

3000 1.0 900.0 A pesar de usar valores grandes realiza su


2000 1.0 600.0 función sin problema, en este caso la solución óptima
1000 1.0 200.0 no necesita fraccionar ningún elemento.
1700

Para los siguientes datos de entrada:

• nº de objetos -> 1000


• Objetos (peso, valor) -> elementos de peso en el rango 20 y 100 y valor entre 15 y 75
• Peso máximo de la mochila -> 200
Obtenemos el siguiente resultado:

20 1.0 74.0
21 1.0 74.0
21 1.0 73.0
20 1.0 69.0
21 1.0 72.0
21 1.0 71.0
21 1.0 66.0
22 1.0 68.0 No tiene problema con gran número de datos,
22 1.0 68.0 sigue consiguiendo el resultado óptimo en un tiempo
20 0.55 33.55 bastante corto.
668.55

Memoria de práctica 7
Código fuente

Clase mochila_voraz.java:

import java.io.File;

/**
* mochila_voraz
*/
public class mochila_voraz {
static String msg = "SINTAXIS: mochila-voraz [-t][-h] [fichero
entrada]" +
"\n-t Traza del algoritmo"
+
"\n-h Muestra este men-
saje" +
"\n[fichero de entrada] nombre del fichero de
entrada" +
"\n[fichero de salida] nombre del fichero de
salida";

public static void main(String[] args) {

ObjectData data = new ObjectData();


ResultData result = new ResultData();

switch (args.length) {
case 0:
data.setFromInputs();
result.setItems(data.getItems());
result.getResult(data.getMaxW(), false, "");
break;
case 1:
if (args[0].equals("-h")) {
System.out.println(msg);
break;
}
if (args[0].equals("-t")) {
data.setFromInputs();

Memoria de práctica 8
result.setItems(data.getItems());
result.getResult(data.getMaxW(), true, "");
} else {
if (new File(args[0]).exists()) {
data.setFromFile(args[0]);
result.setItems(data.getItems());
result.getResult(data.getMaxW(), false, "");
} else {
data.setFromInputs();
result.setItems(data.getItems());
result.getResult(data.getMaxW(), false,
args[0]);
}
}
break;
case 2:
if (args[0].equals("-t")) {
if (new File(args[1]).exists()) {
data.setFromFile(args[1]);
result.setItems(data.getItems());
result.getResult(data.getMaxW(), true, "");
} else {
data.setFromInputs();
result.setItems(data.getItems());
result.getResult(data.getMaxW(), true,
args[1]);
}
} else {
data.setFromFile(args[0]);
result.setItems(data.getItems());
result.getResult(data.getMaxW(), false,
args[1]);
}
break;
case 3:
data.setFromFile(args[1]);
result.setItems(data.getItems());
result.getResult(data.getMaxW(), true, args[2]);
break;

default:
System.err.println(
"Utilice -h para ver como ejecutar el
programa");
break;
}
}
}

Clase ResultData.java:

Memoria de práctica 9
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ResultData {


List<Item> items = new ArrayList<Item>();

public void setItems(List<Item> items) {


this.items = items;
}

public void getResult(int maxW, boolean traza, String fileName){


if (traza) {
System.out.println(
"\n****************** Traza del algoritmo
******************\n"
);
System.out.println(
"Ordenamos los objetos en relacion al valor por
unidad de" +
" peso de forma descendiente."
);
}
orderItems(items, 0, items.size() - 1);
int pesoAcumulado = 0;
float[] fraccionObjeto = new float[items.size()];
float[] beneficioFraccion = new float[items.size()];
float beneficioTotal = 0f;
int contadorObj = 0;
if (traza) {
System.out.println(
"Vamos añadiendo objetos a la mochila hasta
llenarla:"
);
}
while (pesoAcumulado < maxW && contadorObj < items.size()) {
if (pesoAcumulado + items.get(contadorObj).peso <= maxW)
{
if (traza) {
System.out.println(
"\n* El peso del objeto evaluado es: " +
items.get(contadorObj).peso +
", podemos meterlo entero y nos queda
espacio en la mochila"
);
System.out.println(
" Añadimos su valor al valor total dentro
de la mochila"
);
}
fraccionObjeto[contadorObj] = 1f;
beneficioFraccion[contadorObj] =
items.get(contadorObj).valor;
pesoAcumulado += items.get(contadorObj).peso;

Memoria de práctica 10
beneficioTotal += beneficioFraccion[contadorObj] ;
contadorObj++;
} else {
fraccionObjeto[contadorObj] = (float) (maxW -
pesoAcumulado) /
items.get(contadorObj).peso;
beneficioFraccion[contadorObj] =
items.get(contadorObj).valor *
fraccionObjeto[contadorObj];
pesoAcumulado = maxW;
beneficioTotal += beneficioFraccion[contadorObj] ;
if (traza) {
System.out.println(
"\n* El peso del objeto evaluado es: " +
items.get(contadorObj).peso +
", no podemos meterlo entero por tanto
introducimos una fraccion."
);
System.out.println(
" Con " + fraccionObjeto[contadorObj] +
" parte del objeto llenamos la mochila,
añadimos el valor equivalente " +
"a esa fraccion: \"" +
beneficioFraccion[contadorObj] +
"\".\n Alcanzamos el maximo " +
"valor que se puede introducir en la
mochila: \"" + beneficioTotal +
"\" y resolvemos el problema."
);
}
contadorObj++;
}
if (traza) {
System.out.println(
"\n- Peso de la mochila en la iteracion \"" +
contadorObj + "\": " + pesoAcumulado
);
}
}
if (fileName == "") {
if (traza) System.out.println("\nImprimimos los
resultados en consola:");
printResult(fraccionObjeto, beneficioFraccion,
beneficioTotal, contadorObj);
} else {
if (traza) System.out.println("\nIntroducimos los
resultados en el archivo" +
fileName);
resultToFile(fileName, fraccionObjeto,
beneficioFraccion, beneficioTotal, contadorObj);
}
}

private void printResult(float[] frac, float[] bfrac, float bto-


tal, int limit) {
System.out.println("\nResultado:");

Memoria de práctica 11
for (int i = 0; i < limit; i++) {
System.out.println(items.get(i).peso + " " + frac[i] + "
" + bfrac[i]);
}
System.out.println(btotal);
}

private void resultToFile(String name, float[] frac, float[]


bfrac, float btotal, int limit) {
try {
BufferedWriter writer = new BufferedWriter(
new FileWriter(name));
for (int i = 0; i < limit; i++) {
writer.write(
items.get(i).peso + " " +
String.valueOf(frac[i]) +
" " + String.valueOf(bfrac[i]) + "\n"
);
}
writer.write(String.valueOf(btotal));
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}

private void orderItems(List<Item> items, int lowInd, int hiInd)


{

if (lowInd >= hiInd) return ;


float pivot = items.get(hiInd).ratio;
int lpointer = lowInd;
int rpointer = hiInd;
Item temp;
while (lpointer < rpointer) {
while (items.get(lpointer).ratio <= pivot && lpointer <
rpointer) lpointer++;
while (items.get(rpointer).ratio >= pivot && lpointer <
rpointer) rpointer--;
temp = items.get(lpointer);
items.set(lpointer, items.get(rpointer));
items.set(rpointer, temp);
}
temp = items.get(lpointer);
items.set(lpointer, items.get(hiInd));
items.set(hiInd, temp);

orderItems(items, lowInd, lpointer-1);


orderItems(items, lpointer+1, hiInd);
}
}

Memoria de práctica 12
Clase Item.java:

public class Item {


int peso;
int valor;
float ratio;

Item(int peso, int valor){


this.peso = peso;
this.valor = valor;
ratio = (float) peso/valor;
}
}

Clase ObjectData.java:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ObjectData {


int num;
List<Item> items = new ArrayList<Item>();
int maxW;

public void setFromFile(String name) {


try {
BufferedReader reader = new BufferedReader(new Fil-
eReader(name));
num = Integer.parseInt(reader.readLine());
String[] line;
int value;
int weight;
for (int i = 0; i < num; i++) {
line = reader.readLine().split("\\s");
weight = Integer.parseInt(line[0]);
value = Integer.parseInt(line[1]);
items.add(new Item(weight, value));
}
maxW = Integer.parseInt(reader.readLine());
reader.close();
} catch (NumberFormatException | IOException e) {
e.printStackTrace();
}
}

public void setFromInputs() {


Scanner sc = new Scanner(System.in);
System.out.print("Introduczca el numero de objetos: ");

Memoria de práctica 13
num = sc.nextInt();
int value;
int weight;
System.out.println(
"\nAhora introduzca el peso y el valor de cada
objeto por separado");
for (int i = 0; i < num; i++) {
System.out.print("peso " + (i + 1) + ": ");
weight = sc.nextInt();
System.out.print("valor " + (i + 1) + ": ");
value = sc.nextInt();
items.add(new Item(weight, value));
}
System.out.print("Por ultimo introduzca el peso maximo de la
mochila: ");
maxW = sc.nextInt();
sc.close();
}

public List<Item> getItems() {


return items;
}

public int getMaxW() {


return maxW;
}

Memoria de práctica 14

También podría gustarte