Fractional Knapsack in Python
Last Updated :
12 Apr, 2024
Given the weights and profits of N items, in the form of {profit, weight} put these items in a knapsack of capacity W to get the maximum total profit in the knapsack.
In Fractional Knapsack, we can break items for maximizing the total value of the knapsack.
Examples:
Input: arr[] = {{60, 10}, {100, 20}, {120, 30}}, W = 50
Output: 240
Explanation: By taking items of weight 10 and 20 kg and 2/3 fraction of 30 kg.
Hence total price will be 60+100+(2/3)(120) = 240
Input: arr[] = {{500, 30}}, W = 10
Output: 166.667
Naive Approach:
To solve the problem follow the below idea:
The naive approach to solve this problem is to consider all possible fractions of items and choose the one which gives the maximum value and also doesn’t exceed the weight capacity of the knapsack.
Steps:
- Calculate the ratio
value/weight
for each item. - Sort all the items based on this ratio in non-increasing order.
- Initialize
total_value = 0
and current_weight = 0
. - Loop through all the items and:
- If adding the entire item is possible, add it to the knapsack and update
total_value
and current_weight
. - Otherwise, add the fraction of the item to the knapsack and update
total_value
and current_weight
.
- Return
total_value
as the maximum value in the knapsack.
Code
Python3
def fractional_knapsack(values, weights, W):
n = len(values)
# Calculate value/weight ratio for each item
ratios = [(values[i] / weights[i], values[i], weights[i]) for i in range(n)]
# Sort items based on ratio in non-increasing order
ratios.sort(reverse=True)
total_value = 0 # Initialize total value
current_weight = 0 # Initialize current weight
# Loop through all items
for ratio, value, weight in ratios:
if current_weight + weight <= W:
# Add entire item
total_value += value
current_weight += weight
else:
# Add fraction of item
fraction = (W - current_weight) / weight
total_value += value * fraction
break
return total_value
# Example Usage
values1 = [60, 100, 120]
weights1 = [10, 20, 30]
W1 = 50
print("Maximum value in knapsack =", fractional_knapsack(values1, weights1, W1)) # Output: 240
values2 = [40, 100, 50, 60]
weights2 = [20, 10, 40, 30]
W2 = 50
print("Maximum value in knapsack =", fractional_knapsack(values2, weights2, W2)) # Output: 210
OutputMaximum value in knapsack = 240.0
Maximum value in knapsack = 180.0
Time Complexity: O(2N)
Auxiliary Space: O(N)
Fractional Knapsack Problem using Greedy algorithm:
An efficient solution is to use the Greedy approach.
The basic idea of the greedy approach is to calculate the ratio profit/weight for each item and sort the item on the basis of this ratio. Then take the item with the highest ratio and add them as much as we can (can be the whole element or a fraction of it).
This will always give the maximum profit because, in each step it adds an element such that this is the maximum possible profit for that much weight.
Illustration:
Check the below illustration for a better understanding:
Consider the example: arr[] = {{100, 20}, {60, 10}, {120, 30}}, W = 50.
Sorting: Initially sort the array based on the profit/weight ratio. The sorted array will be {{60, 10}, {100, 20}, {120, 30}}.
Iteration:
- For i = 0, weight = 10 which is less than W. So add this element in the knapsack. profit = 60 and remaining W = 50 – 10 = 40.
- For i = 1, weight = 20 which is less than W. So add this element too. profit = 60 + 100 = 160 and remaining W = 40 – 20 = 20.
- For i = 2, weight = 30 is greater than W. So add 20/30 fraction = 2/3 fraction of the element. Therefore profit = 2/3 * 120 + 160 = 80 + 160 = 240 and remaining W becomes 0.
So the final profit becomes 240 for W = 50.
Steps:
- Calculate the ratio
value/weight
for each item. - Sort all the items based on this ratio in non-increasing order.
- Initialize
total_value = 0
and current_weight = 0
. - Loop through all the items and:
- If adding the entire item is possible, add it to the knapsack and update
total_value
and current_weight
. - Otherwise, add the fraction of the item to the knapsack and update
total_value
and current_weight
.
- Return
total_value
as the maximum value in the knapsack.
Below is the implementation of the above approach:
Python3
def greedy_fractional_knapsack(values, weights, W):
n = len(values)
# Calculate value/weight ratio for each item
ratios = [(values[i] / weights[i], values[i], weights[i]) for i in range(n)]
# Sort items based on ratio in non-increasing order
ratios.sort(reverse=True)
total_value = 0 # Initialize total value
current_weight = 0 # Initialize current weight
# Loop through all items
for ratio, value, weight in ratios:
if current_weight + weight <= W:
# Add entire item
total_value += value
current_weight += weight
else:
# Add fraction of item
fraction = (W - current_weight) / weight
total_value += value * fraction
break
return total_value
# Example Usage
values1 = [60, 100, 120]
weights1 = [10, 20, 30]
W1 = 50
print("Maximum value in knapsack (Greedy Approach) =", greedy_fractional_knapsack(values1, weights1, W1)) # Output: 240
values2 = [40, 100, 50, 60]
weights2 = [20, 10, 40, 30]
W2 = 50
print("Maximum value in knapsack (Greedy Approach) =", greedy_fractional_knapsack(values2, weights2, W2)) # Output: 210
OutputMaximum value in knapsack (Greedy Approach) = 240.0
Maximum value in knapsack (Greedy Approach) = 180.0
Time Complexity: O(N * logN)
Auxiliary Space: O(N)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...