Open In App

Fractional Knapsack Queries

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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:

  1. Sort the array by their Value/Weight ratio in descending order.
  2. Find prefix-sum of Weight and Value respectively of the array.
  3.  
    • 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))



Last Updated : 19 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads