The Fractional Knapsack Problem is a classic optimization problem that involves maximizing the total value of items placed inside a knapsack without exceeding its weight capacity. Unlike the 0/1 Knapsack Problem, where each item must be taken or left behind entirely, the Fractional Knapsack Problem allows for taking fractions of an item.
This tutorial will guide you through understanding the problem, implementing a solution using a greedy algorithm, and discussing best practices and real-world applications.
Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible. Unlike the 0/1 Knapsack Problem, you can take fractions of an item.
Consider the following items:
| Item | Weight (kg) | Value ($) |
|---|---|---|
| A | 2 | 3 |
| B | 3 | 4 |
| C | 4 | 5 |
Suppose the knapsack has a weight limit of 7 kg. The goal is to maximize the total value without exceeding the weight limit.
The Fractional Knapsack Problem can be efficiently solved using a greedy algorithm. The idea is to select items based on their value-to-weight ratio, starting with the highest ratio until the knapsack is full or no more items can be added.
function fractionalKnapsack(weights, values, capacity):
n = length(weights)
ratios = []
for i from 0 to n-1:
ratios.append((values[i] / weights[i], weights[i], values[i]))
sort ratios in descending order by value-to-weight ratio
totalValue = 0
remainingCapacity = capacity
for item in ratios:
if remainingCapacity == 0:
break
weight, value = item[1], item[2]
if weight <= remainingCapacity:
totalValue += value
remainingCapacity -= weight
else:
fraction = remainingCapacity / weight
totalValue += value * fraction
remainingCapacity = 0
return totalValue
Here's a complete implementation of the Fractional Knapsack Problem using JavaScript:
function fractionalKnapsack(weights, values, capacity) {
const n = weights.length;
const ratios = [];
for (let i = 0; i < n; i++) {
ratios.push({
ratio: values[i] / weights[i],
weight: weights[i],
value: values[i]
});
}
// Sort items by value-to-weight ratio in descending order
ratios.sort((a, b) => b.ratio - a.ratio);
let totalValue = 0;
let remainingCapacity = capacity;
for (const item of ratios) {
if (remainingCapacity === 0) break;
const weight = item.weight;
const value = item.value;
if (weight <= remainingCapacity) {
totalValue += value;
remainingCapacity -= weight;
} else {
const fraction = remainingCapacity / weight;
totalValue += value * fraction;
remainingCapacity = 0;
}
}
return totalValue;
}
// Example usage
const weights = [2, 3, 4];
const values = [3, 4, 5];
const capacity = 7;
console.log(fractionalKnapsack(weights, values, capacity)); // Output: 8.333333333333334
\(O(n \log n)\) due to sorting, which is efficient for moderate-sized inputs.The Fractional Knapsack Problem is a practical example of how greedy algorithms can be used to solve optimization problems efficiently. By understanding the problem, implementing the solution, and considering best practices, you can apply this algorithm to real-world scenarios where fractional selection is allowed.
Feel free to experiment with different inputs and scenarios to deepen your understanding of this classic problem.