This is my solution to an assignment on the fractional Knapsack problem. I take as problem input the following pieces of information:
- The number of item types
- The total weight limit
- For each item type, the total available weight of that item type and the value per unit of weight
The output is the amount of weight to select of each item type that maximizes the total value subject to the weight constraint. The program works fine, but I wanted to understand what could have been better with the code.
import java.util.List;
import java.util.LinkedList;
import java.util.Scanner;
public class Knapsack {
// This will define the length of the arrays, numOfItems and wholeValue;
int arrayLength; // The number of items to be entered.
int totalQty; // The total Quantity that we must check against.
int[] numOfItems; // Holds the quantity
int[] wholeValue; // Holds the value
// This is the list that keeps the weight (value/quantity) for each item
// and its index in either array numOfItems / wholeValue.
// The index is useful to retrieve the quantity later on.
// The array wholeValue has no use after the weights have been calculated.
class weightsAndIndex{
double Weight;
int Index;
}
List<weightsAndIndex> myObj;
// Initialise all the values.
public Knapsack(int n, int m)
{
numOfItems = new int[n];
wholeValue = new int[n];
arrayLength = n;
totalQty = m;
myObj = new LinkedList<>();
}
// Sort the weights as value/quantity.
public void sortWeights()
{
double max;
double temp;
int i = 0;
int index=0;
weightsAndIndex tmpObj;
for (i = 0; i < arrayLength; i++)
{
// Calculate the weight of all the items in a loop
temp = (double)wholeValue[i]/(double)numOfItems[i];
// Create a new object to store the weight and the index
tmpObj = new weightsAndIndex();
tmpObj.Index = i;
tmpObj.Weight = temp;
// Find the sorted position of the current weight in the list.
while (index <= myObj.size() -1 && myObj.get(index).Weight > temp)
{
index++;
}
// Add the object at the index location to the list.
myObj.add(index, tmpObj);
// Reset the index to start from the start again.
index = 0;
}
}
public int min(int x, int y)
{
if (x < y)
return x;
return y;
}
public double findFinalWeight ()
{
double tmp;
int tempIndex;
int numAtIndex;
double finalWeight = 0;
int tempMin;
int qty = totalQty;
boolean exceeded = false;
for (int i = 0; i < arrayLength && exceeded != true; i++)
{
// We start with the heaviest weight.
// We need to get the corresponding index entry to access its quantity
tempIndex = myObj.get(i).Index;
numAtIndex = numOfItems[tempIndex];
// Between the quantity yet to be filled and the quantity corresponding to this weight,
// we can only serve the minimum of the two.
// Effectively, if we have 50 quantities yet to be filled but only 30 of "this" item,
// we can serve up only 30.
tempMin = min(qty, numAtIndex);
// Add the quantity.
finalWeight = finalWeight + myObj.get(i).Weight * tempMin;
if (qty == tempMin)
{
exceeded = true;
}
else
{
qty = qty - tempMin;
}
}
return finalWeight;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int totalNum;
int totalVal;
Scanner in = new Scanner(System.in);
totalNum = in.nextInt();
totalVal = in.nextInt();
Knapsack obj = new Knapsack(totalNum, totalVal);
// Read next set of inputs
for (int i = 0; i < obj.arrayLength; i++)
{
obj.wholeValue[i] = in.nextInt();
obj.numOfItems[i] = in.nextInt();
}
obj.sortWeights();
System.out.println(obj.findFinalWeight());
}
}
min
may be replaced byMath.min
\$\endgroup\$