Fractional Knapsack
Description
You are given two arrays, val[] and wt[]: item i is worth val[i] and weighs wt[i] kilograms. You also have a knapsack that can carry at most capacity kilograms.
You may put any of the items in the knapsack, and you may cut an item and take only part of it. A part keeps its share of the value: half of an item is worth half of its value.
Return the maximum total value you can carry, as a decimal number rounded to 6 decimal places.
Examples
Example 1
Input: val = [60, 40, 90, 50], wt = [20, 10, 45, 50], capacity = 60
Output: 160.000000
Explanation: Per kilogram the items are worth 3, 4, 2 and 1. Take all of item 1 (10 kg, worth 40) and all of item 0 (20 kg, worth 60). That leaves 30 kg of space, filled with 30 of item 2's 45 kg: 90 × 30 / 45 = 60. The total is 40 + 60 + 60 = 160.
Example 2
Input: val = [10, 20], wt = [5, 5], capacity = 100
Output: 30.000000
Explanation: The items weigh 10 kg together, well under 100, so both go in whole.
Example 3
Input: val = [100], wt = [30], capacity = 10
Output: 33.333333
Explanation: The only item is too heavy, so take 10 of its 30 kg: 100 × 10 / 30 = 33.333333.
Constraints
- val.size() = wt.size() ≤ 10^5
- 1 ≤ val[i], wt[i] ≤ 10^4
- 1 ≤ capacity ≤ 10^9
Editorial
Brute Force
Intuition
Think in kilograms. Because items can be cut, the bag is really capacity kilograms to fill, and each kilogram of item i is worth val[i] / wt[i]. The best bag is one in which every kilogram is as valuable as it can be. So fill it with the most valuable kilograms first: take the item with the highest value per kilogram, as much of it as fits, then the next best, and so on, until the bag is full or the items run out.

Why this is always best. Suppose some bag leaves part of a better item out while carrying some kilograms of a worse one. Swap one kilogram of the worse item for one kilogram of the better one: the weight stays the same and the value goes up. So a best bag never does that. It takes items in order of value per kilogram, and only the last item it touches can be cut.
This works only because items can be cut. In 0/1 knapsack, where every item is all or nothing, the same rule can fail:

The rule takes A and B, then cannot fit C and leaves 20 kg empty, for 160, while B and C together give 220. With cutting, no space is ever wasted and the swap argument above always holds. That is why 0/1 knapsack needs dynamic programming and fractional knapsack does not.
The simplest way to follow the rule. Every round, look through all the items for the one with the most value per kilogram that is not used up yet, and take as much of it as fits.
Comparing value per kilogram without dividing. val[i] / wt[i] > val[j] / wt[j] says the same as val[i] × wt[j] > val[j] × wt[i], because both weights are positive. The products are whole numbers of at most 10^8, so the comparison is exact.
Step-by-Step Explanation
We trace Example 1. The top row is each item's value with its value per kilogram underneath, and the second row is how many of its kilograms are still out of the bag. Each round is a full scan, with the chosen item in blue, followed by taking it: green when taken whole, amber when cut.
Step 1: The bag holds 60 kg. Items are worth 3, 4, 2 and 1 per kilogram.
Step 2: Round 1: scan all 4 items; the best one left is item 1, 4 per kg.
Step 3: Take all 10 kg of item 1: +40. Total 40, 50 kg left.
Step 4: Round 2: scan all 4 items; the best one left is item 0, 3 per kg.
Step 5: Take all 20 kg of item 0: +60. Total 100, 30 kg left.
Step 6: Round 3: scan all 4 items; the best one left is item 2, 2 per kg.
Step 7: Cut item 2: 30 of 45 kg, +60. Total 160, 0 kg left.
Step 8: The bag is full: return 160.000000, after 12 looks at items.
Brute Force — Scan for the Best Item, Every Round — Example 1, a 60 kg bag. Top row: item values, with value per kilogram underneath. Second row: kilograms still out of the bag.
Algorithm
- Set
left[i] = wt[i]for every item, andtotal = 0. - While
capacity > 0:- Scan every item and pick
best: the one withleft[best] > 0and the most value per kilogram. - If there is none, every item is already in the bag: stop.
- Let
take = min(left[best], capacity). Addval[best] × take / wt[best]tototal, and subtracttakefrom bothleft[best]andcapacity.
- Scan every item and pick
- Return
total.
Code
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
double fractionalKnapsack(vector<int>& val, vector<int>& wt, int capacity) {
int n = val.size();
vector<long long> left(wt.begin(), wt.end()); // kilograms of each item not yet in the bag
double total = 0;
long long cap = capacity;
while (cap > 0) {
int best = -1;
for (int i = 0; i < n; i++) // the item with the most value per kilogram among those not used up
if (left[i] > 0 && (best == -1 || (long long)val[i] * wt[best] > (long long)val[best] * wt[i])) best = i;
if (best == -1) break; // every item is already in the bag
long long take = min(left[best], cap);
total += (double)val[best] * take / wt[best];
left[best] -= take;
cap -= take;
}
return total;
}
};class Solution:
def fractionalKnapsack(self, val, wt, capacity):
n = len(val)
left = wt[:] # kilograms of each item not yet in the bag
total = 0.0
while capacity > 0:
best = -1
for i in range(n): # the item with the most value per kilogram among those not used up
if left[i] > 0 and (best == -1 or val[i] * wt[best] > val[best] * wt[i]):
best = i
if best == -1: # every item is already in the bag
break
take = min(left[best], capacity)
total += val[best] * take / wt[best]
left[best] -= take
capacity -= take
return totalclass Solution {
public double fractionalKnapsack(int[] val, int[] wt, int capacity) {
int n = val.length;
long[] left = new long[n]; // kilograms of each item not yet in the bag
for (int i = 0; i < n; i++) left[i] = wt[i];
double total = 0;
long cap = capacity;
while (cap > 0) {
int best = -1;
for (int i = 0; i < n; i++) // the item with the most value per kilogram among those not used up
if (left[i] > 0 && (best == -1 || (long) val[i] * wt[best] > (long) val[best] * wt[i])) best = i;
if (best == -1) break; // every item is already in the bag
long take = Math.min(left[best], cap);
total += (double) val[best] * take / wt[best];
left[best] -= take;
cap -= take;
}
return total;
}
}Complexity Analysis
Time Complexity: O(n²). Every round either uses up an item or fills the bag, so there are at most n rounds, and each one scans all n items.
Space Complexity: O(n) for left.
Why This Approach Is Not Efficient
Each round scans every item again, although the ranking of the items never changes: the item that is second best now becomes the best as soon as the first one is used up. Measured in Python, 1,000 items take 0.017 s, 2,000 take 0.069 s, 4,000 take 0.285 s and 8,000 take 1.1 s, four times longer every time the count doubles. At that rate the full 10^5 items would take about 3 minutes.
Since the order never changes, it can be worked out once, by sorting.
Better Approach - Sort by Value per Kilogram
Intuition
Sort once, then fill. Put the items in order of value per kilogram, highest first, and walk down the list. While an item fits whole, take it. The first item that does not fit is cut to fill exactly the space that is left, and then the bag is full.
Sorting by value per kilogram. C++ and Java compare two items with the cross-multiplication above, so no decimals are involved. Python sorts by the decimal val[i] / wt[i], which is exact enough here: with whole numbers up to 10^4, two different ratios differ by at least 1/10^8, far more than a decimal's rounding error, and equal ratios such as 2/4 and 1/2 give exactly the same decimal. Items with equal value per kilogram can go in any order, since a kilogram of one is worth exactly a kilogram of the other.
The total. A whole item adds exactly val[i]. Only the cut item needs a division, val[i] × space / wt[i].
When everything fits. If the capacity is at least the total weight, the loop takes every item and never cuts one, as in Example 2. The totals stay below 10^9, and a double holds them far more precisely than the 6 decimal places asked for.
Step-by-Step Explanation
We trace Example 1 again. The first frame shows the items as given and the second shows them sorted by value per kilogram; then the bag is filled from the left. Items taken whole are green, and the cut item is amber.
Step 1: The items as given, worth 3, 4, 2 and 1 per kilogram.
Step 2: Sort once by value per kilogram: item 1, item 0, item 2, item 3.
Step 3: Item 1 (10 kg) fits whole: +40, total 40, 50 kg left.
Step 4: Item 0 (20 kg) fits whole: +60, total 100, 30 kg left.
Step 5: Item 2 does not fit whole: cut it, 90 × 30 / 45 = 60. Total 160. Stop.
Step 6: Return 160.000000. Item 3 was never needed.
Sort by Value per Kilogram, Then Fill — Example 1: the items are sorted once by value per kilogram, then taken from the left until the bag is full.
Algorithm
- Sort the item indices by
val[i] / wt[i], highest first. - Set
total = 0. For each itemiin that order:- if
wt[i] ≤ capacity, addval[i]tototaland subtractwt[i]fromcapacity; - otherwise add
val[i] × capacity / wt[i]tototaland stop.
- if
- Return
total.
Code
#include <algorithm>
#include <numeric>
#include <vector>
using namespace std;
class Solution {
public:
double fractionalKnapsack(vector<int>& val, vector<int>& wt, int capacity) {
vector<int> order(val.size());
iota(order.begin(), order.end(), 0);
sort(order.begin(), order.end(), [&](int a, int b) { // a before b when val[a]/wt[a] > val[b]/wt[b], without dividing
return (long long)val[a] * wt[b] > (long long)val[b] * wt[a];
});
double total = 0;
long long cap = capacity;
for (int i : order) {
if (wt[i] <= cap) { // the whole item fits
total += val[i];
cap -= wt[i];
} else { // only part of it fits, and then the bag is full
total += (double)val[i] * cap / wt[i];
break;
}
}
return total;
}
};class Solution:
def fractionalKnapsack(self, val, wt, capacity):
# most value per kilogram first; with whole numbers up to 10^4, equal ratios give equal decimals
order = sorted(range(len(val)), key=lambda i: val[i] / wt[i], reverse=True)
total = 0.0
for i in order:
if wt[i] <= capacity: # the whole item fits
total += val[i]
capacity -= wt[i]
else: # only part of it fits, and then the bag is full
total += val[i] * capacity / wt[i]
break
return totalimport java.util.Arrays;
class Solution {
public double fractionalKnapsack(int[] val, int[] wt, int capacity) {
Integer[] order = new Integer[val.length];
for (int i = 0; i < order.length; i++) order[i] = i;
// a before b when val[a]/wt[a] > val[b]/wt[b], compared without dividing
Arrays.sort(order, (a, b) -> Long.compare((long) val[b] * wt[a], (long) val[a] * wt[b]));
double total = 0;
long cap = capacity;
for (int i : order) {
if (wt[i] <= cap) { // the whole item fits
total += val[i];
cap -= wt[i];
} else { // only part of it fits, and then the bag is full
total += (double) val[i] * cap / wt[i];
break;
}
}
return total;
}
}Complexity Analysis
Time Complexity: O(n log n) for the sort; the filling afterwards is O(n). Measured in Python, 0.026 s for 10^5 items.
Space Complexity: O(n) for the sorted list of indices.
Why This Approach Is Not Efficient
Sorting puts every item in its exact place, but the answer depends on one question only: which item gets cut. Everything before it goes in whole, everything after it stays out, and the order among those items is never used. Sorting pays O(n log n) to arrange items whose order does not matter.
It is still a very good answer, and it is GfG's expected complexity. The next approach finds the cut item directly, in O(n) expected time.
Optimal Approach - Find the Cut Item Without Sorting
Intuition
Find the cut item, not the whole order. Pick one item at random as a pivot and split the items, by value per kilogram, into three groups: better than the pivot, equal to it, and worse. Then weigh the better group.
- If it weighs at least as much as the space left, the bag fills up inside it, so the cut item is in there. Everything else can be forgotten; continue with just the better group.
- Otherwise, the whole better group goes in, in any order. Then, if the pivot's group (the items worth exactly as much per kilogram as the pivot) fills the rest, cut it and stop; all of it is worth the same per kilogram, so which of them is cut does not matter. If not, it goes in whole too, and the search continues among the worse items with the space that is left.

This is the idea behind quickselect, the method for finding the k-th smallest number without sorting.
Why about n steps. Each round reads the remaining items once. Half of the time, a random pivot lands in the middle half of them, and then at most three quarters of them survive into the next round. So on average the group shrinks steadily, and the total work, n plus a fraction of n plus a smaller fraction, stays a small multiple of n. Always picking a bad pivot would cost O(n²), which is why the pivot is picked at random.
Step-by-Step Explanation
We trace Example 1. The pivot is picked at random; in this run the picks happen to be item 3, then item 1, then item 2. The pivot is blue, the group being weighed is amber, items in the bag are green and the cut item is orange. An item set aside for good shows a dot instead of its weight in the second row.
Step 1: Four candidates, nothing sorted, 60 kg of space.
Step 2: Pivot item 3 (1/kg): items 0, 1 and 2 are better than it (75 kg), against 60 kg of space.
Step 3: 75 ≥ 60: keep only the better group. Item 3 is set aside for good.
Step 4: Pivot item 1 (4/kg): nothing is better than it (0 kg), against 60 kg of space.
Step 5: Nothing is better. Item 1 fits whole: total 40, 50 kg left. Continue with the worse items.
Step 6: Pivot item 2 (2/kg): item 0 is better than it (20 kg), against 50 kg of space.
Step 7: The better group goes in whole (+60). Item 2 is the cut item: +60, total 160. Return 160.000000.
Find the Cut Item With a Random Pivot — Example 1. Each round picks a pivot, weighs the items that are better per kilogram, and keeps only the side where the bag fills up.
Algorithm
- Let
itemsbe every index, andtotal = 0. - While
itemsis not empty andcapacity > 0:- Pick a random pivot
pfromitems, and splititemsintobetter,sameandworseby comparingval[i] × wt[p]withval[p] × wt[i]. - If the better group weighs at least
capacity, keep onlybetterand repeat. - Otherwise add the better group's value to
totaland subtract its weight fromcapacity. If thesamegroup weighs at least the remainingcapacity, returntotal + val[p] × capacity / wt[p]. If not, add it whole too and keep onlyworse.
- Pick a random pivot
- Return
total; this is reached when everything fitted.
Code
#include <numeric>
#include <random>
#include <vector>
using namespace std;
class Solution {
public:
double fractionalKnapsack(vector<int>& val, vector<int>& wt, int capacity) {
vector<int> items(val.size());
iota(items.begin(), items.end(), 0);
mt19937 rng(12345);
double total = 0;
long long cap = capacity;
while (!items.empty() && cap > 0) {
int p = items[rng() % items.size()]; // a random pivot keeps the expected work linear
vector<int> better, worse;
long long wBetter = 0, wSame = 0, vBetter = 0, vSame = 0;
for (int i : items) {
long long l = (long long)val[i] * wt[p], r = (long long)val[p] * wt[i];
if (l > r) { better.push_back(i); wBetter += wt[i]; vBetter += val[i]; }
else if (l == r) { wSame += wt[i]; vSame += val[i]; }
else worse.push_back(i);
}
if (wBetter >= cap) { // the bag fills up inside the better group
items.swap(better);
continue;
}
total += vBetter; // every better item goes in whole
cap -= wBetter;
if (wSame >= cap) return total + (double)val[p] * cap / wt[p]; // the pivot's group fills the rest
total += vSame;
cap -= wSame;
items.swap(worse);
}
return total;
}
};import random
class Solution:
def fractionalKnapsack(self, val, wt, capacity):
items = list(range(len(val)))
total = 0.0
while items and capacity > 0:
p = random.choice(items) # a random pivot keeps the expected work linear
better = [i for i in items if val[i] * wt[p] > val[p] * wt[i]]
same = [i for i in items if val[i] * wt[p] == val[p] * wt[i]]
worse = [i for i in items if val[i] * wt[p] < val[p] * wt[i]]
w_better = sum(wt[i] for i in better)
if w_better >= capacity: # the bag fills up inside the better group
items = better
continue
total += sum(val[i] for i in better) # every better item goes in whole
capacity -= w_better
w_same = sum(wt[i] for i in same)
if w_same >= capacity: # the pivot's group fills the rest; all of it has the pivot's value per kilogram
return total + val[p] * capacity / wt[p]
total += sum(val[i] for i in same)
capacity -= w_same
items = worse
return totalimport java.util.ArrayList;
import java.util.List;
import java.util.Random;
class Solution {
public double fractionalKnapsack(int[] val, int[] wt, int capacity) {
List<Integer> items = new ArrayList<>();
for (int i = 0; i < val.length; i++) items.add(i);
Random rng = new Random(12345);
double total = 0;
long cap = capacity;
while (!items.isEmpty() && cap > 0) {
int p = items.get(rng.nextInt(items.size())); // a random pivot keeps the expected work linear
List<Integer> better = new ArrayList<>(), worse = new ArrayList<>();
long wBetter = 0, wSame = 0, vBetter = 0, vSame = 0;
for (int i : items) {
long l = (long) val[i] * wt[p], r = (long) val[p] * wt[i];
if (l > r) { better.add(i); wBetter += wt[i]; vBetter += val[i]; }
else if (l == r) { wSame += wt[i]; vSame += val[i]; }
else worse.add(i);
}
if (wBetter >= cap) { // the bag fills up inside the better group
items = better;
continue;
}
total += vBetter; // every better item goes in whole
cap -= wBetter;
if (wSame >= cap) return total + (double) val[p] * cap / wt[p]; // the pivot's group fills the rest
total += vSame;
cap -= wSame;
items = worse;
}
return total;
}
}Complexity Analysis
Time Complexity: O(n) expected. Each round reads the remaining items once, and the group left shrinks by a steady fraction on average.
Space Complexity: O(n) for the groups.
Measured. In C++, where both methods run as compiled code, the pivot method is far faster: 0.007 s against 0.071 s for sorting at 10^6 items, and 0.073 s against 0.974 s at 10^7. In Python the two are about equal at 10^5 items, 0.027 s against 0.026 s, because Python's sort runs as compiled code while the pivot method's loops run line by line; at 10^6 items the pivot method is a little ahead, 0.30 s against 0.36 s. At this problem's limits either one is fine; the pivot method is the one whose cost grows only in step with n.