Fractional Knapsack Problem in DSA Python - Time & Space Complexity
We want to understand how the time needed to solve the Fractional Knapsack Problem changes as the number of items grows.
Specifically, how the sorting and selection steps affect the total work done.
Analyze the time complexity of the following code snippet.
items = [(60, 10), (100, 20), (120, 30)] # (value, weight)
capacity = 50
# Sort items by value per weight
items.sort(key=lambda x: x[0]/x[1], reverse=True)
total_value = 0
for value, weight in items:
if capacity == 0:
break
take = min(weight, capacity)
total_value += take * (value / weight)
capacity -= take
print(total_value)
This code sorts items by their value per weight and then takes as much as possible from the best items until the capacity is full.
- Primary operation: Sorting the list of items by value per weight.
- How many times: Sorting compares items roughly n log n times for n items.
- Secondary operation: Looping through the sorted items once to pick fractions.
- How many times: Loop runs at most n times.
As the number of items increases, sorting takes more time, growing faster than just looping.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * log(10) ≈ 33 operations for sorting + 10 for picking |
| 100 | About 100 * log(100) ≈ 664 operations for sorting + 100 for picking |
| 1000 | About 1000 * log(1000) ≈ 9966 operations for sorting + 1000 for picking |
Pattern observation: Sorting dominates and grows a bit faster than the number of items, while picking grows linearly.
Time Complexity: O(n log n)
This means the time needed grows a bit faster than the number of items because of sorting, which is the main cost.
[X] Wrong: "The loop to pick items is the slowest part, so the time complexity is O(n)."
[OK] Correct: Sorting takes more time than just looping because it compares items many times, making it the dominant step.
Understanding how sorting affects the overall time helps you explain your solution clearly and shows you know where the main work happens.
"What if the items were already sorted by value per weight? How would the time complexity change?"
Practice
Fractional Knapsack Problem?Solution
Step 1: Understand problem objective
The fractional knapsack problem aims to maximize the total value of items taken, allowing fractions of items to fit within the weight limit.Step 2: Compare options
Only Maximize total value by taking fractions of items within weight limit correctly describes maximizing value with fractional items. Others describe incorrect goals.Final Answer:
Maximize total value by taking fractions of items within weight limit -> Option AQuick Check:
Goal = Maximize value with fractions [OK]
- Thinking only whole items can be taken
- Confusing value maximization with weight minimization
- Ignoring the fractional part of items
Solution
Step 1: Identify ratio for sorting
Value-to-weight ratio is value divided by weight, so ratio = x[1]/x[0].Step 2: Check sorting code
items.sort(key=lambda x: x[1]/x[0], reverse=True) sorts items by this ratio descending, which is correct for fractional knapsack.Final Answer:
items.sort(key=lambda x: x[1]/x[0], reverse=True) -> Option BQuick Check:
Sort by value/weight descending [OK]
- Reversing numerator and denominator
- Sorting by sum or difference instead of ratio
- Not using reverse=True for descending order
items = [(10, 60), (20, 100), (30, 120)]
capacity = 50
items.sort(key=lambda x: x[1]/x[0], reverse=True)
total_value = 0
for w, v in items:
if capacity >= w:
capacity -= w
total_value += v
else:
total_value += v * (capacity / w)
break
print(round(total_value, 2))Solution
Step 1: Sort items by value/weight ratio
Ratios: (60/10)=6, (100/20)=5, (120/30)=4. Sorted order: (10,60), (20,100), (30,120).Step 2: Add items until capacity is full
Take full 10 weight: value=60, capacity=40 left.
Take full 20 weight: value=60+100=160, capacity=20 left.
Take fraction of last item: fraction=20/30=2/3, value=160 + 120*(2/3)=160 + 80=240.
But code prints rounded total_value after break, so total_value=240.Final Answer:
240.00 -> Option AQuick Check:
Sum values with fractions = 240.00 [OK]
- Not sorting items by ratio
- Adding fractions incorrectly
- Rounding errors
def fractional_knapsack(items, capacity):
items.sort(key=lambda x: x[0]/x[1], reverse=True)
total_value = 0
for w, v in items:
if capacity >= w:
capacity -= w
total_value += v
else:
total_value += v * (capacity / w)
break
return total_value
print(fractional_knapsack([(10, 60), (20, 100), (30, 120)], 50))Solution
Step 1: Check sorting key
Sorting uses x[0]/x[1] which is weight/value, but ratio should be value/weight (x[1]/x[0]).Step 2: Verify other parts
Loop variables and capacity update are correct; function returns after loop.Final Answer:
Sorting ratio is reversed; should be value/weight, not weight/value -> Option DQuick Check:
Sort by value/weight, not weight/value [OK]
- Using weight/value instead of value/weight for sorting
- Swapping weight and value in loop
- Not updating capacity after fraction
Solution
Step 1: Calculate value/weight ratios and sort
Ratios: (30/5)=6, (40/10)=4, (45/15)=3.
Sorted order: (5,30), (10,40), (15,45).Step 2: Add items until capacity full
Take full 5 weight: value=30, capacity=15 left.
Take full 10 weight: value=30+40=70, capacity=5 left.
Take fraction of last item: fraction=5/15=1/3, value=70 + 45*(1/3)=70 + 15=85.Final Answer:
85.0 -> Option CQuick Check:
Sum values with fractions = 85.0 [OK]
- Not sorting by ratio
- Taking items in wrong order
- Calculating fraction incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
