foreach-ui logo
codeLanguages
account_treeDSA

Quick Actions

quizlock Random Quiz
trending_uplock Progress
  • 1
  • 2
  • 3
  • 4
  • quiz
Algorithms
  • Understand why value/weight ratio is the greedy choice for fractional knapsack
  • See why greedy works for fractional but fails for 0/1 knapsack
  • Learn to implement fractional knapsack in O(n log n) time

Fractional Knapsack Problem

You're robbing a jewelry store. Your backpack holds 50 kg. You have:

  • Gold bars: 60 kg total, worth $6000 ($100/kg)
  • Diamonds: 20 kg total, worth $4000 ($200/kg)
  • Silver: 30 kg total, worth $1500 ($50/kg)

You can break items and take fractions. What do you take?

Naive approach: take the most valuable total. Gold is worth $6000. But it weighs 60 kg—won't fit.

Better: look at value per kilogram. Diamonds are $200/kg, gold is $100/kg, silver is $50/kg.

Greedy strategy: take items with the highest value per kilogram first.

Capacity: 50 kg

1. Take all diamonds: 20 kg, $4000. Remaining: 30 kg
2. Take gold: need 30 kg, have 60 kg. Take 30/60 = 50% of it.
   Value: 30 kg × $100/kg = $3000. Remaining: 0 kg

Total: $4000 + $3000 = $7000

That's optimal. If you took gold first (only 50 kg of it), you'd get $5000. If you took silver, even worse.

The Algorithm

def fractional_knapsack(items, capacity):
    # Calculate value/weight ratio for each item
    items_with_ratio = []
    for value, weight in items:
        ratio = value / weight
        items_with_ratio.append((ratio, value, weight))
    
    # Sort by ratio, descending
    items_with_ratio.sort(reverse=True)
    
    total_value = 0
    remaining = capacity
    
    for ratio, value, weight in items_with_ratio:
        if weight <= remaining:
            # Take the whole item
            total_value += value
            remaining -= weight
        else:
            # Take a fraction
            fraction = remaining / weight
            total_value += value * fraction
            remaining = 0
            break  # Knapsack full
    
    return total_value

For our jewelry store:

Items: [(6000, 60), (4000, 20), (1500, 30)]
Ratios: [100, 200, 50]

With ratios: [(200, 4000, 20), (100, 6000, 60), (50, 1500, 30)]

Capacity: 50

Iteration 1: ratio=200, value=4000, weight=20
  20 <= 50, take whole item
  total_value = 4000, remaining = 30

Iteration 2: ratio=100, value=6000, weight=60
  60 > 30, take fraction
  fraction = 30/60 = 0.5
  total_value = 4000 + 6000×0.5 = 7000
  remaining = 0
  
Return 7000

Time complexity: O(n log n) for sorting + O(n) for greedy loop = O(n log n).

Why Greedy Works Here

The value/weight ratio tells you how "efficient" an item is. Taking the most efficient items first maximizes total value.

Can we do better by taking less efficient items? No. Suppose we skip a high-ratio item to take a low-ratio one. We'd get less value per unit weight, reducing the total. Swapping back to the high-ratio item always improves the solution.

This is the greedy choice property: the locally optimal choice (highest ratio) leads to a globally optimal solution.

A More Complex Example

Items:

Item 1: value=60, weight=10 → ratio=6.0
Item 2: value=100, weight=20 → ratio=5.0
Item 3: value=120, weight=30 → ratio=4.0

Capacity: 50

Sorted by ratio: Item 1 (6.0), Item 2 (5.0), Item 3 (4.0)

Take Item 1: weight=10, value=60. Remaining: 40
Take Item 2: weight=20, value=100. Remaining: 20
Take Item 3: need 30, have 20. Take 20/30.
  value = 120 × (20/30) = 80. Remaining: 0

Total: 60 + 100 + 80 = 240

If we took them in a different order:

  • Item 3 first: 30 kg, $120. Then Item 2: 20 kg, $100. Total: $220 (worse)
  • Item 2 first: 20 kg, $100. Then Item 1: 10 kg, $60. Then Item 3: 20 kg of it, $80. Total: $240 (same as greedy)

Actually, the second approach also gave $240. Let me recalculate:

  • Item 2 (20 kg, $100), Item 1 (10 kg, $60), Item 3 (20/30, $80) = $240

Both orderings that prioritize high ratios give the same result. That's expected—multiple optimal solutions can exist, but greedy finds one of them.

Fractional vs 0/1 Knapsack

Fractional: Can take fractions. Greedy works.

0/1: Must take whole items. Greedy fails.

For the same items with capacity 50:

  • Greedy (by ratio): Item 1 (10 kg, $60), Item 2 (20 kg, $100). Can't fit Item 3. Total: $160
  • Optimal: Item 2 (20 kg, $100), Item 3 (30 kg, $120). Total: $220

Greedy gives $160, but optimal is $220. For 0/1 knapsack, you need dynamic programming.

Why does greedy fail for 0/1? Because you can't take fractions. The greedy choice might leave unused capacity that can't be filled efficiently. DP considers all combinations to find the true optimum.

Proof of Optimality

Suppose there's an optimal solution that doesn't follow greedy's order. It must skip some high-ratio item A for a lower-ratio item B.

Swap them: replace some of B with A. Since A has a higher ratio, you get more value for the same weight (or more value with less weight, leaving room for more items).

This swap improves or maintains the solution, contradicting the assumption that the non-greedy solution was optimal.

Therefore, greedy is optimal for fractional knapsack.

Practical Applications

Resource allocation: Allocating limited budget across projects with different ROI (return on investment). Prioritize high ROI projects.

Network bandwidth: Allocating bandwidth to data streams. Prioritize streams with highest priority/bandwidth ratio.

Investment portfolio: With divisible assets, invest in highest return/risk ratio first.

Loading cargo: Shipping containers with weight limits. Load highest value/weight items first.

Implementation Details

Edge cases:

  • Empty items list: return 0
  • Zero capacity: return 0
  • All items fit: take all, no fractions needed

Floating point precision: When calculating ratios and fractions, be careful with floating-point arithmetic. For exact results, use integer arithmetic where possible.

Ties in ratio: If two items have the same ratio, the order doesn't matter—either can come first without affecting optimality.

The Key Insight

Fractional knapsack is greedy-friendly because you can take partial items. This flexibility means the locally optimal choice (highest ratio) doesn't block better global solutions—you can always adjust by taking more or less of subsequent items.

For 0/1 knapsack, you can't adjust. Taking an item commits you, potentially blocking combinations that would be better. That's why you need DP.

Recognizing when a problem allows "fractional" choices vs "all-or-nothing" choices tells you whether greedy will work or if you need DP.

Comparison Table

Aspect Fractional Knapsack 0/1 Knapsack
Items Can take fractions Whole items only
Algorithm Greedy Dynamic programming
Time O(n log n) O(nW) or O(n × capacity)
Optimality Greedy is optimal Greedy is NOT optimal
Why Fractions allow adjustments All-or-nothing blocks adjustments

Fractional knapsack is the easier problem. Master it, understand why greedy works, and you'll appreciate why 0/1 knapsack needs something more powerful.

© 2026 forEach. All rights reserved.

Privacy Policy•Terms of Service