Greedy: Fractional Knapsack Problem
Greedy: Fractional Knapsack Problem
Imagine you're a logistics manager filling a cargo plane with valuable shipments, but you can't fit everything. Some shipments can be split open to take just a portion of their contents. Your goal is to maximize profit, and you need a fast, reliable strategy. This is the essence of the Fractional Knapsack Problem, a classic optimization challenge where a greedy algorithm provides a perfect, efficient solution. Understanding this problem teaches you a powerful problem-solving paradigm and clarifies a fundamental distinction in computational complexity: when an item's divisibility makes a problem drastically easier to solve.
Problem Definition and Core Idea
The Fractional Knapsack Problem is formally defined as follows: you have a knapsack (or container) with a maximum weight capacity . You are given a set of items, each with a positive value and a positive weight . The key difference from other knapsack problems is that you can take a fractional part of any item. If you take a fraction (where ) of item , you gain a value of and use of the knapsack's capacity. Your objective is to maximize the total value of items in the knapsack without exceeding its weight capacity.
The core insight for solving it optimally is to prioritize items not by their total value or lowest weight, but by their value density or value-to-weight ratio, . An item with a high ratio gives you more value per unit of weight consumed. A greedy algorithm makes a series of locally optimal choices—at each step, taking as much as possible of the available item with the highest ratio—with the hope that this leads to a globally optimal solution. For this specific problem, that hope is fulfilled.
The Greedy Algorithm: Step-by-Step
The algorithm is straightforward and efficient, running in time due to the required sorting step.
- Calculate Ratios: For each item , compute its value-to-weight ratio, .
- Sort: Sort all items in decreasing order of their ratio .
- Iterate and Fill: Initialize the knapsack as empty (remaining capacity = ) and total value = .
- Go through the sorted list of items.
- For each item, if you can take the whole item ( remaining capacity), take all of it. Add to the total value and subtract from the remaining capacity.
- If you cannot take the whole item (remaining capacity ), take a fraction of it. The fraction is
remaining capacity / w_i. Add(remaining capacity / w_i) * v_ito the total value. The knapsack is now full (remaining capacity becomes ).
- Terminate: The algorithm stops when the knapsack is full or all items have been considered.
Worked Example: Let capacity . Items: (Value, Weight) = A(60, 10), B(100, 20), C(120, 30).
- Calculate ratios: , , .
- Sort: A (ratio 6), B (ratio 5), C (ratio 4).
- Fill:
- Take all of A. Value += 60, Capacity left = .
- Take all of B. Value += 100, Capacity left = .
- Cannot take all of C (weight 30 > 20). Take a fraction: of C. Value += .
- Total Optimal Value = .
Proof of Optimality
Why does this greedy approach guarantee the best possible solution? The proof hinges on the ability to take fractions and the concept of opportunity cost. If the knapsack contains any amount of an item with a lower ratio while some amount of a higher-ratio item (not necessarily from the same input set) is left out, you can always swap some weight from the lower-ratio item for an equal weight of the higher-ratio item. This swap would increase the total value without changing the total weight, proving the original solution wasn't optimal. Therefore, an optimal solution must fill the knapsack by taking as much as possible of the highest-ratio items first, exactly what our algorithm does. This is often formalized using an exchange argument.
Contrast with the 0/1 Knapsack Problem
This contrast is crucial for understanding problem complexity. The 0/1 Knapsack Problem has identical inputs except for one constraint: you must take an item entirely or leave it behind—no fractions allowed. This indivisibility changes everything.
A greedy strategy based on value-to-weight ratio fails for the 0/1 variant. Consider a knapsack with and items: (60, 10, ratio=6), (100, 20, ratio=5), (120, 30, ratio=4). The greedy fractional solution (A, B, 2/3 of C) yields 240, but this isn't allowed in 0/1. The greedy 0/1 algorithm would take A (value 60, weight 10), then B (value 100, weight 20), then have 20 capacity left but could not take C (weight 30). Total value = 160. However, the true 0/1 optimal solution is to take B and C: value = 100 + 120 = 220. The greedy choice for the first item (the highest ratio) precluded a better overall combination.
The 0/1 Knapsack Problem is NP-Hard, requiring more complex techniques like Dynamic Programming (DP) to find an exact solution, which runs in pseudo-polynomial time . The fractional version, solvable greedily in , is in complexity class P. This highlights how a small change in problem constraints—divisibility—can fundamentally alter the computational complexity and solution strategy.
Common Pitfalls
- Applying the Greedy Ratio Strategy to 0/1 Knapsack: As demonstrated, sorting by ratio and taking whole items does not guarantee an optimal solution for the 0/1 problem. This is the most frequent conceptual error. Remember, the greedy algorithm's correctness for the fractional version is not transferable.
- Incorrect Sorting or Fraction Calculation: Always sort in decreasing order of the value-to-weight ratio. When calculating the final fraction, it's easy to mistakenly use the remaining value instead of the remaining capacity. The correct fraction is
remaining_capacity / item_weight. - Overlooking Algorithm Efficiency: While implementing, a naive approach might involve repeatedly searching for the highest-ratio item, leading to time. The standard efficient implementation requires a one-time sort () followed by a linear scan ().
- Misunderstanding the Problem Scope: Assume fractional items are allowed only if the problem explicitly states it or uses language like "you can take parts of items." In many real-world and algorithmic contexts, the default assumption is the 0/1 variant.
Summary
- The Fractional Knapsack Problem is an optimization task where items can be taken in fractions, and the objective is to maximize total value without exceeding a weight limit.
- The optimal solution is achieved using a greedy algorithm that repeatedly takes as much as possible of the item with the highest value-to-weight ratio.
- The algorithm's optimality can be proven using an exchange argument, which shows that any solution not following the greedy order can be improved.
- This problem stands in sharp contrast to the 0/1 Knapsack Problem, where items are indivisible. The greedy ratio strategy fails for 0/1, which instead requires Dynamic Programming.
- The divisibility property makes the fractional version computationally easy (polynomial time), while the 0/1 version is NP-Hard, illustrating how problem constraints fundamentally impact complexity.