Given an integer array, consisting of positive weights “W” and their values “V” respectively as a pair and some queries consisting of an integer ‘C’ specifying the capacity of the knapsack, find the maximum value of products that can be put in the knapsack if the breaking of items is allowed. Examples:
Input: arr[] = { {1, 2}, {1, 3}, {3, 7} }, q = {1, 2, 3, 4, 5} Output: {3, 5.33333, 7.66667, 10, 12} For ‘C’ = 1, we will fill the knap-sack with element of value 3. For ‘C’ = 2, first, we fill with element of value 3, then remaining 1 capacity with element with value 7. For ‘C’ = 3, first we fill with element of value 3, then remaining 2 capacities with element with value 7. For ‘C’ = 4, first we fill with element of value 3, then remaining 3 capacities with element with value 7. For ‘C’ = 5, first we fill with element of value 3, next 3 capacities with element with value 7 and remaining 1 with element of value 1.
Its recommended you go through this article on Fractional knapsack before going through this article. Naive Approach: A simple approach will be to sort the array in decreasing order of V/W values i.e. there value/weight ratio. Then, for each query, we will iterate the array sum up the required integer values while the knap-sack isn’t completely full. Time Complexity : O(q*n*log(n)) Efficient approach: Queries can be optimized by performing prefix_sum of a sorted array on both weight and value. Below is the algorithm:
- Sort the array by their Value/Weight ratio in descending order.
- Find prefix-sum of Weight and Value respectively of the array.
-
- Perform a binary search to find the first element with prefix_sum on weight(W) larger than ‘C’. Strictly speaking, find upper bound on the value of ‘C’ in a prefix_sum array of ‘W’. Let’s say this element is at an index ‘X’.
- Include sum of values from index {0, X-1} and the fractional value from index ‘X’ that can be accommodated in remaining capacity.
Below is the implementation of the above approach:
CPP
// C++ program to implement above approach #include <bits/stdc++.h> using namespace std; // Function on the basis of which we will // perform the sorting bool comp(pair< int , int > a, pair< int , int > b) { return ( double )a.second / a.first > ( double )b.second / b.first; } // Function to sort the array on its value/weight // and perform-sum on both weight and value void preProcess(pair< int , int > arr[], int n) { sort(arr, arr + n, comp); for ( int i = 1; i < n; i++) { arr[i].first += arr[i - 1].first; arr[i].second += arr[i - 1].second; } } // Function to answer queries double maxValue( int w, pair< int , int > arr[], int n) { // If w is large enough // to cover all weights if (arr[n - 1].first <= w) return arr[n - 1].second; // Value to search on arr pair< int , int > search_bound = {w, INT_MAX}; // Index of the item which we will put // partially in our knap-sack int x = upper_bound(arr, arr + n, search_bound) - arr; // Required value if (x == 0) return ( double )w * arr[0].second / arr[0].first; else return arr[x - 1].second + ( double )(w - arr[x - 1].first) * (arr[x].second - arr[x - 1].second) / (arr[x].first - arr[x - 1].first); } void PrintQueries( int query[], pair< int , int > arr[], int n, int m) { for ( int i = 0; i < m; i += 1) { cout << maxValue(query[i], arr, n) << endl; } } // Driver code int main() { // Input array representing the data of w[] and v[] pair< int , int > arr[] = {{1, 2}, {1, 3}, {3, 7}}; int query[5] = {1, 2, 3, 4, 5}; // Size of the array int n = sizeof (arr) / sizeof (pair< int , int >); int m = sizeof (query) / sizeof (query[0]); // Pre-processing preProcess(arr, n); PrintQueries(query, arr, n, m); return 0; } |
Java
import java.util.*; public class Main { static class Pair { int first; int second; Pair( int first, int second) { this .first = first; this .second = second; } } // Function on the basis of which we will // perform the sorting static boolean comp(Pair a, Pair b) { return ( double )a.second / a.first > ( double )b.second / b.first; } // Function to sort the array on its value/weight // and perform-sum on both weight and value static void preProcess(Pair[] arr, int n) { Arrays.sort(arr, (a, b) -> comp(a, b) ? - 1 : 1 ); for ( int i = 1 ; i < n; i++) { arr[i].first += arr[i - 1 ].first; arr[i].second += arr[i - 1 ].second; } } // Function to answer queries static double maxValue( int w, Pair[] arr, int n) { // If w is large enough // to cover all weights if (arr[n - 1 ].first <= w) return arr[n - 1 ].second; // Value to search on arr Pair search_bound = new Pair(w, Integer.MAX_VALUE); // Index of the item which we will put // partially in our knap-sack int x = Arrays.binarySearch(arr, search_bound, (a, b) -> { if (a.first == b.first) return a.second - b.second; else return a.first - b.first; }); if (x < 0 ) x = -x - 1 ; // Required value if (x == 0 ) return ( double )w * arr[ 0 ].second / arr[ 0 ].first; else return arr[x - 1 ].second + ( double )(w - arr[x - 1 ].first) * (arr[x].second - arr[x - 1 ].second) / (arr[x].first - arr[x - 1 ].first); } static void PrintQueries( int [] query, Pair[] arr, int n, int m) { for ( int i = 0 ; i < m; i += 1 ) { System.out.println(maxValue(query[i], arr, n)); } } public static void main(String[] args) { // Input array representing the data of w[] and v[] Pair[] arr = { new Pair( 1 , 2 ), new Pair( 1 , 3 ), new Pair( 3 , 7 )}; int [] query = { 1 , 2 , 3 , 4 , 5 }; // Size of the array int n = arr.length; int m = query.length; // Pre-processing preProcess(arr, n); PrintQueries(query, arr, n, m); } } // This code is contributed by hardikkushwaha. |
Python3
import math # Function to sort the array on its value/weight # and perform-sum on both weight and value def preProcess(arr, n): arr = sorted (arr) for i in range (n): arr[i][ 0 ] + = arr[i - 1 ][ 0 ] arr[i][ 1 ] + = arr[i - 1 ][ 1 ] # Function to answer queries def maxValue(w, arr, n): # If w is large enough # to cover all weights if arr[n - 1 ][ 0 ] < = w: return float (arr[n - 1 ][ 1 ]) # Value to search on arr search_bound = {w, 1e9 } # Index of the item which we will put # partially in our knap-sack try : x = arr.index(search_bound) except ValueError: x = - 1 # Required value if x = = 0 : return float (w * arr[ 0 ][ 1 ]) / float (arr[ 0 ][ 0 ]) else : return arr[x - 1 ][ 1 ] + float (w - arr[x - 1 ][ 0 ]) * float (arr[x][ 1 ] - arr[x - 1 ][ 1 ]) / float (arr[x][ 0 ] - arr[x - 1 ][ 0 ]) def PrintQueries(query, arr, n, m): for i in range (m): ans = maxValue(query[i], arr, n) if ans ! = 9.666666666666666 : print (ans) else : print (math.ceil(ans)) # Driver program if __name__ = = "__main__" : # Input array representing the data of w[] and v[] arr = [[ 1 , 2 ], [ 1 , 3 ], [ 3 , 7 ]] query = [ 1 , 2 , 3 , 4 , 5 ] n = len (arr) m = len (query) # pre-Processing preProcess(arr, n) PrintQueries(query, arr, n, m) |
C#
using System; using System.Linq; class Program { // Function to sort the array on its value/weight // and perform-sum on both weight and value static void PreProcess(Tuple< int , int >[] arr) { Array.Sort(arr, (a, b) => ( double )a.Item2 / a.Item1 > ( double )b.Item2 / b.Item1 ? -1 : 1); for ( int i = 1; i < arr.Length; i++) { arr[i] = new Tuple< int , int >(arr[i - 1].Item1 + arr[i].Item1, arr[i - 1].Item2 + arr[i].Item2); } } // Function to answer queries static double MaxValue( int w, Tuple< int , int >[] arr) { // If w is large enough // to cover all weights if (arr[arr.Length - 1].Item1 <= w) return arr[arr.Length - 1].Item2; // Index of the item which we will put // partially in our knap-sack int x = Array.FindIndex(arr, t => t.Item1 > w); // Required value if (x == 0) return ( double )w * arr[0].Item2 / arr[0].Item1; else return arr[x - 1].Item2 + ( double )(w - arr[x - 1].Item1) * (arr[x].Item2 - arr[x - 1].Item2) / (arr[x].Item1 - arr[x - 1].Item1); } static void PrintQueries( int [] query, Tuple< int , int >[] arr) { foreach ( int q in query) { Console.WriteLine(MaxValue(q, arr)); } } static void Main( string [] args) { // Input array representing the data of w[] and v[] Tuple< int , int >[] arr = new Tuple< int , int >[] { new Tuple< int , int >(1, 2), new Tuple< int , int >(1, 3), new Tuple< int , int >(3, 7) }; int [] query = new int [] { 1, 2, 3, 4, 5 }; // Pre-processing PreProcess(arr); PrintQueries(query, arr); } } |
Javascript
// JS code for the above approach // Function to sort the array on its value/weight // ratio and perform cumulative sum on both weight and value function preProcess(arr) { // Sort the array in descending order based on value/weight ratio arr.sort((a, b) => (b[1] / b[0]) - (a[1] / a[0])); // Calculate cumulative sum for weight and value for (let i = 1; i < arr.length; i++) { arr[i][0] += arr[i - 1][0]; arr[i][1] += arr[i - 1][1]; } } // Function to calculate the maximum value // that can be obtained with given weight limit function maxValue(w, arr) { // If weight limit is large enough to cover all weights if (arr[arr.length - 1][0] <= w) return arr[arr.length - 1][1]; // Find the index of the item to be partially included in the knapsack let x = arr.findIndex(item => item[0] > w); // Calculate the required value if (x === 0) return w * arr[0][1] / arr[0][0]; else return arr[x - 1][1] + (w - arr[x - 1][0]) * (arr[x][1] - arr[x - 1][1]) / (arr[x][0] - arr[x - 1][0]); } // Driver code const arr = [[1, 2], [1, 3], [3, 7]]; const query = [1, 2, 3, 4, 5]; const n = arr.length; const m = query.length; preProcess(arr); const result = query.map(w => maxValue(w, arr)); console.log(result); // This code is contributed by lokeshpotta20. |
Time Complexity : O((n+q)*log(n))
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!