|
| 1 | +<h1 align="center">Fractional - Knapsack</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Fractional Knapsack](https://www.geeksforgeeks.org/problems/fractional-knapsack-1587115620/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=practice_card) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +### Problem Explanation |
| 10 | +The problem you're referring to is the **Fractional Knapsack Problem**, which is a classic problem in optimization. Here, you are given a knapsack with a certain capacity and a set of items. Each item has a value and a weight. The goal is to maximize the total value in the knapsack without exceeding its capacity. |
| 11 | + |
| 12 | +**Key points:** |
| 13 | +- You can take fractions of items (i.e., you don’t have to take the whole item if it exceeds the remaining capacity). |
| 14 | +- The challenge is to maximize the total value without exceeding the knapsack’s capacity. |
| 15 | + |
| 16 | +### Problem Description: |
| 17 | +You are given: |
| 18 | +1. A list of `n` items, each with a `value[i]` and `weight[i]`. |
| 19 | +2. A `capacity` of the knapsack. |
| 20 | + |
| 21 | +You are required to fill the knapsack in such a way that the **total value is maximized**, while not exceeding the knapsack’s capacity. You can take fractions of the items if necessary. |
| 22 | + |
| 23 | +### Example: |
| 24 | +**Input:** |
| 25 | +- `value[] = {60, 100, 120}` |
| 26 | +- `weight[] = {10, 20, 30}` |
| 27 | +- `capacity = 50` |
| 28 | + |
| 29 | +**Steps to solve the problem:** |
| 30 | +1. First, calculate the **value per unit weight** for each item: |
| 31 | + - Item 1: ( frac{60}{10} = 6 ) |
| 32 | + - Item 2: ( frac{100}{20} = 5 ) |
| 33 | + - Item 3: ( frac{120}{30} = 4 ) |
| 34 | + |
| 35 | +2. Sort the items by **value per unit weight** in descending order: |
| 36 | + - Sorted order: Item 1 → Item 2 → Item 3 |
| 37 | + |
| 38 | +3. Fill the knapsack with items in this sorted order, and take fractions as needed: |
| 39 | + - First, take the full Item 1 (weight = 10, value = 60). Remaining capacity = 50 - 10 = 40. |
| 40 | + - Next, take the full Item 2 (weight = 20, value = 100). Remaining capacity = 40 - 20 = 20. |
| 41 | + - Finally, take a fraction of Item 3 (weight = 20, value = 120). We can take only 20 units from this item, which gives a fraction of ( frac{20}{30} times 120 = 80 ). |
| 42 | + |
| 43 | +4. The total value of the knapsack is ( 60 + 100 + 80 = 240 ). |
| 44 | + |
| 45 | +**Output:** The maximum value that can be obtained is 240. |
| 46 | + |
| 47 | +### Greedy Approach (Step by Step): |
| 48 | + |
| 49 | +The **Greedy Approach** for solving the Fractional Knapsack Problem can be summarized in the following steps. Let’s break down the greedy approach used in the code you previously shared: |
| 50 | + |
| 51 | +### 1. **Calculate Value per Unit Weight:** |
| 52 | +For each item, calculate the value-to-weight ratio. This ratio helps determine the **"value density"** of the item (how much value we get per unit of weight). |
| 53 | + |
| 54 | +For item (i): |
| 55 | +` |
| 56 | +{value per unit weight} = frac{{value}[i]}{{weight}[i]} |
| 57 | +` |
| 58 | + |
| 59 | +**Example:** |
| 60 | +```cpp |
| 61 | +val = [60, 100, 120`wt = [10, 20, 30 |
| 62 | +```` |
| 63 | +For each item: |
| 64 | +- Item 1: ( frac{60}{10} = 6.0 ) |
| 65 | +- Item 2: ( frac{100}{20} = 5.0 ) |
| 66 | +- Item 3: ( frac{120}{30} = 4.0 ) |
| 67 | + |
| 68 | +### 2. **Sort Items by Value per Unit Weight:** |
| 69 | +Sort the items in descending order based on their value per unit weight. This ensures that we prioritize the most valuable items (i.e., those that give the most value per unit weight). |
| 70 | + |
| 71 | +Sorted items by value per unit weight: |
| 72 | +- Item 1 (6.0) |
| 73 | +- Item 2 (5.0) |
| 74 | +- Item 3 (4.0) |
| 75 | + |
| 76 | +### 3. **Greedily Select Items:** |
| 77 | +Start filling the knapsack from the sorted list, taking items in the order of highest value per unit weight. |
| 78 | + |
| 79 | +#### **a. Take Full Items (if capacity allows):** |
| 80 | +If the knapsack has enough capacity to accommodate the current item, take the full item, and reduce the remaining capacity accordingly. |
| 81 | + |
| 82 | +#### **b. Take Fraction of Item (if capacity doesn’t allow):** |
| 83 | +If the knapsack doesn’t have enough capacity to take the full item, take the fraction of the item that can fit in the remaining capacity. The value added will be proportional to the weight that we take. |
| 84 | + |
| 85 | +For each item, we: |
| 86 | +- If the item’s weight is less than or equal to the remaining capacity, we add the full value of the item. |
| 87 | +- If the item’s weight is greater than the remaining capacity, we add the fractional value based on the remaining capacity. |
| 88 | + |
| 89 | +### 4. **Return the Total Value:** |
| 90 | +Once the knapsack is filled, return the total value accumulated. |
| 91 | + |
| 92 | +## Problem Solution |
| 93 | +```cpp |
| 94 | +class Solution { |
| 95 | + public: |
| 96 | + // Function to solve the Fractional Knapsack problem |
| 97 | + double fractionalKnapsack(vector<int>& val, vector<int>& wt, int capacity) { |
| 98 | + // Create a vector to store pairs where each pair consists of the per unit value |
| 99 | + // and the corresponding (value, weight) pair for each item |
| 100 | + vector<pair<double, pair<int, int>>> v; |
| 101 | + |
| 102 | + // Step 1: Calculate the per unit value (value/weight) for each item and store it |
| 103 | + for(int i = 0; i < val.size(); i++){ |
| 104 | + double perUnitValue = 1.0 * val[i] / wt[i]; // Calculate per unit value for the item |
| 105 | + v.push_back({perUnitValue, {val[i], wt[i]}}); // Store the per unit value along with the (value, weight) pair |
| 106 | + } |
| 107 | + |
| 108 | + // Step 2: Sort the vector 'v' in decreasing order based on per unit value |
| 109 | + sort(v.begin(), v.end(), [](pair<double, pair<int, int>>& a, pair<double, pair<int, int>>& b){ |
| 110 | + return a.first > b.first; // Comparator to sort by per unit value in descending order |
| 111 | + }); |
| 112 | + |
| 113 | + // Step 3: Initialize the total value of the knapsack to 0 |
| 114 | + double totalValue = 0.0; |
| 115 | + |
| 116 | + // Step 4: Start filling the knapsack |
| 117 | + for(int i = 0; i < val.size(); i++){ |
| 118 | + int currentWeight = v[i].second.second; // Get the weight of the current item |
| 119 | + int currentValue = v[i].second.first; // Get the value of the current item |
| 120 | + double perUnitValue = v[i].first; // Get the per unit value of the current item |
| 121 | + |
| 122 | + // Step 5: Check if the current item can be fully added to the knapsack |
| 123 | + if(capacity >= currentWeight) { |
| 124 | + totalValue += currentValue; // Add the full value of the item |
| 125 | + capacity -= currentWeight; // Decrease the remaining capacity of the knapsack |
| 126 | + } else { |
| 127 | + // If the current item cannot be fully added, add the fractional part of it |
| 128 | + totalValue += capacity * perUnitValue; // Add the value for the fractional weight |
| 129 | + break; // Once the knapsack is full, break out of the loop |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + // Step 6: Return the total value of the knapsack |
| 134 | + return totalValue; |
| 135 | + } |
| 136 | +}; |
| 137 | + |
| 138 | +``` |
| 139 | + |
| 140 | +## Problem Solution Explanation |
| 141 | +#### **Step 1: Initialize a vector `v`** |
| 142 | +```cpp |
| 143 | +vector<pair<double, pair<int, int>>> v; |
| 144 | +``` |
| 145 | +- **Purpose**: `v` is a vector of pairs where each element is a pair of: |
| 146 | + - `double`: the per unit value (value/weight) of an item. |
| 147 | + - `pair<int, int>`: contains the value and weight of the item. |
| 148 | + |
| 149 | +#### **Step 2: Calculate the per unit value for each item** |
| 150 | +```cpp |
| 151 | +for(int i = 0; i < val.size(); i++){ |
| 152 | + double perUnitValue = 1.0 * val[i] / wt[i]; // Calculate per unit value for the item |
| 153 | + v.push_back({perUnitValue, {val[i], wt[i]}}); // Store the per unit value along with the (value, weight) pair |
| 154 | +} |
| 155 | +``` |
| 156 | +- **Purpose**: This loop calculates the **value per unit weight** for each item. |
| 157 | + - For each item, `perUnitValue` is calculated as the value of the item divided by its weight (`val[i] / wt[i]`). |
| 158 | + - The pair is then pushed into the vector `v` with the first element as the per unit value and the second element as the pair `(value, weight)`. |
| 159 | + |
| 160 | +**Example**: |
| 161 | +Let’s assume we have: |
| 162 | + |
| 163 | +```cpp |
| 164 | +val = [60, 100, 120`wt = [10, 20, 30 |
| 165 | +```` |
| 166 | +For each item, the per unit value would be: |
| 167 | +- Item 1: ( frac{60}{10} = 6.0 ) |
| 168 | +- Item 2: ( frac{100}{20} = 5.0 ) |
| 169 | +- Item 3: ( frac{120}{30} = 4.0 ) |
| 170 | + |
| 171 | +`v` will look like this after the loop: |
| 172 | + |
| 173 | +```cpp |
| 174 | +v = [(6.0, (60, 10)), (5.0, (100, 20)), (4.0, (120, 30)) |
| 175 | +```` |
| 176 | + |
| 177 | +#### **Step 3: Sort items by per unit value in descending order** |
| 178 | +```cpp |
| 179 | +sort(v.begin(), v.end(), [](pair<double, pair<int, int>>& a, pair<double, pair<int, int>>& b){ |
| 180 | + return a.first > b.first; // Comparator to sort by per unit value in descending order |
| 181 | +}); |
| 182 | +``` |
| 183 | +- **Purpose**: Sort the vector `v` in **descending order** of the per unit value. This ensures that we first consider the most valuable items (items that give the most value per unit of weight). |
| 184 | + - A lambda function is used as the comparator to sort by the first element of each pair (`a.first > b.first`), which is the per unit value. |
| 185 | +
|
| 186 | +**Example**: |
| 187 | +After sorting, `v` will look like this: |
| 188 | +```cpp |
| 189 | +v = [(6.0, (60, 10)), (5.0, (100, 20)), (4.0, (120, 30)) |
| 190 | +```` |
| 191 | +
|
| 192 | +#### **Step 4: Initialize the total value of the knapsack** |
| 193 | +```cpp |
| 194 | +double totalValue = 0.0; |
| 195 | +``` |
| 196 | +- **Purpose**: Initialize `totalValue` to 0. This variable will store the accumulated value of the items placed in the knapsack. |
| 197 | + |
| 198 | +#### **Step 5: Start filling the knapsack** |
| 199 | +```cpp |
| 200 | +for(int i = 0; i < val.size(); i++){ |
| 201 | + int currentWeight = v[i].second.second; // Get the weight of the current item |
| 202 | + int currentValue = v[i].second.first; // Get the value of the current item |
| 203 | + double perUnitValue = v[i].first; // Get the per unit value of the current item |
| 204 | +``` |
| 205 | +- **Purpose**: Iterate through each item in the sorted vector `v`. For each item, extract the weight (`currentWeight`), value (`currentValue`), and per unit value (`perUnitValue`). |
| 206 | +
|
| 207 | +**Example**: |
| 208 | +- For the first item in the sorted vector `v`: |
| 209 | + - `currentWeight = 10`, `currentValue = 60`, `perUnitValue = 6.0`. |
| 210 | +
|
| 211 | +#### **Step 6: Add items to the knapsack** |
| 212 | +```cpp |
| 213 | +if(capacity >= currentWeight) { |
| 214 | + totalValue += currentValue; // Add the full value of the item |
| 215 | + capacity -= currentWeight; // Decrease the remaining capacity of the knapsack |
| 216 | +} else { |
| 217 | + // If the current item cannot be fully added, add the fractional part of it |
| 218 | + totalValue += capacity * perUnitValue; // Add the value for the fractional weight |
| 219 | + break; // Once the knapsack is full, break out of the loop |
| 220 | +} |
| 221 | +``` |
| 222 | +- **Purpose**: Check if the current item can be fully added to the knapsack based on the remaining capacity: |
| 223 | + - If the current item’s weight is less than or equal to the remaining capacity of the knapsack, add the full value of the item and update the remaining capacity. |
| 224 | + - If the item’s weight is more than the remaining capacity, add only the fractional value (based on how much of the item can fit) and then stop since the knapsack is full. |
| 225 | + |
| 226 | +**Example**: |
| 227 | +Let’s assume the capacity of the knapsack is 50. |
| 228 | +- For the first item (weight = 10, value = 60), we can add the full item: |
| 229 | + - `totalValue += 60`, and `capacity -= 10` → `totalValue = 60`, `capacity = 40`. |
| 230 | +- For the second item (weight = 20, value = 100), we can add the full item: |
| 231 | + - `totalValue += 100`, and `capacity -= 20` → `totalValue = 160`, `capacity = 20`. |
| 232 | +- For the third item (weight = 30, value = 120), we can add only a fraction (capacity = 20): |
| 233 | + - `totalValue += 20 * 4.0 = 80`, and the knapsack is full (`capacity = 0`). |
| 234 | + |
| 235 | +#### **Step 7: Return the total value** |
| 236 | +```cpp |
| 237 | +return totalValue; |
| 238 | +``` |
| 239 | +- **Purpose**: Return the total accumulated value of the items in the knapsack. |
| 240 | + |
| 241 | +### Time Complexity: |
| 242 | +- **Sorting the vector** takes (O(n log n)), where (n) is the number of items. |
| 243 | +- **Iterating through the items** takes (O(n)). |
| 244 | +Thus, the overall time complexity is dominated by the sorting step, so the time complexity is **(O(n log n))**. |
| 245 | + |
| 246 | +### Space Complexity: |
| 247 | +- The space complexity is (O(n)) because we store the items and their per unit values in the vector `v`. |
0 commit comments