14.7 Fractional Knapsack
The fractional knapsack problem is one of the clearest examples of a greedy algorithm producing an optimal solution.
14.7 Fractional Knapsack
The fractional knapsack problem is one of the clearest examples of a greedy algorithm producing an optimal solution. Unlike many optimization problems where local decisions can lead to poor global outcomes, fractional knapsack possesses a structure that makes the greedy choice immediately obvious once the correct perspective is adopted.
The problem is important for two reasons. First, it demonstrates a powerful exchange argument. Second, it provides a useful contrast with the 0/1 knapsack problem, where a nearly identical problem statement requires dynamic programming rather than a greedy strategy.
The difference between the two problems is only a single word:
fractional
That one change completely alters the mathematical structure of the problem.
Problem
A knapsack has capacity:
$$ W $$
There are (n) items.
Each item has:
- Weight (w_i)
- Value (v_i)
Unlike the 0/1 knapsack problem, an item may be divided into arbitrary fractions.
Goal:
Maximize total value without exceeding capacity.
Example
Capacity:
$$ W = 50 $$
Items:
| Item | Weight | Value |
|---|---|---|
| A | 10 | 60 |
| B | 20 | 100 |
| C | 30 | 120 |
At first glance, many choices appear possible.
A better view emerges when we compute value density.
Value Density
Define:
$$ d_i = \frac{v_i}{w_i} $$
For the example:
| Item | Weight | Value | Density |
|---|---|---|---|
| A | 10 | 60 | 6 |
| B | 20 | 100 | 5 |
| C | 30 | 120 | 4 |
Density measures value gained per unit weight.
Higher density means greater efficiency.
Key Greedy Observation
Suppose one kilogram of capacity remains.
Would we rather fill it with:
- An item producing value 6 per kilogram?
- An item producing value 4 per kilogram?
The answer is obvious.
Every unit of capacity should be allocated to the highest-density item available.
This immediately suggests the greedy rule:
Always take as much as possible from the item with highest value density.
Greedy Algorithm
Step 1
Compute:
$$ \frac{v_i}{w_i} $$
for every item.
Step 2
Sort items by decreasing density.
Step 3
Process items in that order.
For each item:
- Take the whole item if possible.
- Otherwise take the remaining fraction that fits.
Continue until capacity is exhausted.
Example Walkthrough
Sorted order:
| Item | Density |
|---|---|
| A | 6 |
| B | 5 |
| C | 4 |
Take A
Weight:
$$ 10 $$
Value:
$$ 60 $$
Remaining capacity:
$$ 40 $$
Take B
Weight:
$$ 20 $$
Value:
$$ 100 $$
Remaining capacity:
$$ 20 $$
Take Fraction of C
C weighs:
$$ 30 $$
Only:
$$ 20 $$
capacity remains.
Take:
$$ \frac{20}{30} = \frac{2}{3} $$
of C.
Value obtained:
$$ 120 \times \frac{2}{3} = 80 $$
Total Value
$$ 60 + 100 + 80 = 240 $$
Final solution:
| Item | Fraction Taken |
|---|---|
| A | 1 |
| B | 1 |
| C | 2/3 |
Total value:
$$ 240 $$
This is optimal.
Geometric Interpretation
Imagine capacity as a horizontal line.
Each item contributes value at a constant rate equal to its density.
Density 6
Density 5
Density 4
To maximize total value, capacity should always be allocated to the steepest available slope first.
The greedy strategy becomes almost inevitable.
Why the Greedy Choice Works
Suppose an optimal solution violates the greedy rule.
There exists:
- A higher-density item partially unused.
- A lower-density item partially used.
Let:
$$ d_h > d_l $$
Transfer a small amount of weight:
$$ \Delta $$
from the lower-density item to the higher-density item.
Value change:
$$ (d_h - d_l)\Delta $$
Since:
$$ d_h > d_l $$
the value strictly increases.
The original solution therefore cannot be optimal.
This contradiction proves:
Every optimal solution must fully utilize higher-density items before lower-density items.
The greedy choice is safe.
Exchange Argument
Suppose:
| Item | Density |
|---|---|
| A | 6 |
| B | 4 |
An alleged optimal solution uses:
5 units of B
while leaving:
5 units of A
unused.
Exchange those 5 units.
Value gain:
$$ (6-4)\times5 = 10 $$
The objective improves.
The original solution was not optimal.
Repeated exchanges eventually transform any optimal solution into the greedy solution.
This is a classic exchange argument.
Proof of Optimality
Greedy Choice Property
The highest-density item must be used as much as possible.
Optimal Substructure
After taking the highest-density item, the remaining capacity forms a smaller fractional knapsack problem.
Recursive Reduction
The same reasoning applies repeatedly.
Therefore the greedy algorithm constructs an optimal solution.
Implementation
Go
type Item struct {
Weight float64
Value float64
}
Sorting by density:
sort.Slice(items, func(i, j int) bool {
return items[i].Value/items[i].Weight >
items[j].Value/items[j].Weight
})
Selection loop:
remaining := capacity
total := 0.0
for _, item := range items {
if remaining == 0 {
break
}
if item.Weight <= remaining {
total += item.Value
remaining -= item.Weight
} else {
fraction := remaining / item.Weight
total += fraction * item.Value
remaining = 0
}
}
Complexity Analysis
Sorting:
$$ O(n\log n) $$
Selection pass:
$$ O(n) $$
Total:
$$ O(n\log n) $$
Space:
$$ O(1) $$
excluding sorting overhead.
Why 0/1 Knapsack Is Different
Now remove the word "fractional".
Items can no longer be split.
Example:
| Item | Weight | Value |
|---|---|---|
| A | 10 | 60 |
| B | 20 | 100 |
| C | 30 | 120 |
Capacity:
$$ 50 $$
Density order:
A -> B -> C
Greedy result:
$$ 60 + 100 = 160 $$
Optimal result:
$$ 100 + 120 = 220 $$
The greedy algorithm fails.
The exchange argument collapses because fractions cannot be transferred.
This demonstrates how a small modeling change can completely alter algorithm design.
Real-World Applications
Cargo Loading
Some commodities can be divided freely.
Examples:
- Grain
- Oil
- Sand
- Chemicals
Bandwidth Allocation
Network capacity can often be divided continuously.
Investment Allocation
Capital may be distributed fractionally among assets.
Resource Scheduling
Computational resources may be allocated proportionally.
In these situations the fractional assumption is realistic.
Common Mistakes
Sorting by Value
High-value items may have poor density.
Sorting by Weight
Light items may contribute little value.
Forgetting Fractions
The final item is often only partially selected.
Applying the Same Logic to 0/1 Knapsack
This is the most common error.
The proof relies completely on divisibility.
Without divisibility, the greedy argument fails.
Relationship to Previous Sections
Activity selection chooses:
Earliest finish time
Huffman coding chooses:
Lowest frequencies
Fractional knapsack chooses:
Highest value density
The exact criterion changes, but the proof pattern remains the same:
- Identify a locally optimal choice.
- Show any optimal solution can be transformed to include it.
- Reduce the problem size.
- Repeat.
This pattern defines the essence of greedy algorithm design.
Takeaway
Fractional knapsack is a canonical greedy optimization problem. By sorting items according to value density and always taking as much as possible from the highest-density item, an optimal solution can be constructed in (O(n\log n)) time. The correctness proof follows from an exchange argument showing that any solution allocating capacity to a lower-density item before a higher-density one can be improved. The problem also provides a valuable lesson: small changes in problem constraints can completely change which algorithmic techniques apply, as demonstrated by the dramatic contrast with the 0/1 knapsack problem.