Knapsack Algorithm with Proper Ratio and Weight Limit

Problem: You are a juice producer looking for the best suppliers for your business. Suppliers sell concentrates that contain 3 ingredients: X: Y: Z in various proportions. Your juice should have these proportions as 1: 1: 1, otherwise it will not be tasty. The weight of the concentrate is the sum of its ingredients in pounds, and all suppliers sell their concentrates at the same price, but your truck can transport up to 400 pounds of concentrates. Find the best suppliers for your business: buy (find) as many pounds of concentrate as you can (but less than 400 pounds), knowing that the ratio of ingredients other than 1: 1: 1 will not be acceptable.

Input: The first line tells you how many concentrates are sold on the market (less than 200) The next n lines refer to the proportions of the ingredients of the concentrates X: Y: Z (in pounds)

Conclusion: The first line should be the sum of the weight of the concentrate ingredients that you will buy (less than 400 pounds) The second line should indicate how many concentrates you must buy to get this amount, keeping the correct proportions.

Example:

in:
4 //how many concentrates are sold on the market
1 2 3 //first concentrate contains 1lb of X, 2lbs of Y, 3 lbs of Z
0 4 1
1 3 4
1 1 1
2 1 0

out: 
12 //4lbs of ingredient X + 4lbs Y + 4lbs Z
3 //we're buying three concentrates: the first one, fourth and fifth (1 2 3; 1 1 1; 2 1 0) so we're getting the biggest amount of it with 1:1:1 ratio of ingredients

My solution: My solution was brute force, which is very slow when there are many suppliers, because its complexity is 2 ^ (n-2) - this algorithm will simply create all possible combinations of concentrates that we could buy, and it will check the proportions are 1: 1: 1, if so, it will compare them and find the one with the most common ingredients under 400 pounds.

, , .

+4
2

400/3 = 133, , 133 . , DP array[134][134][134], , .

2,4 , ( 200). , 500 . .

for ( i = 133; i > 0; i-- )
    if ( array[i][i][i] > 0 )
        the answer is array[i][i][i]
+3

, , user3386109. (, ) : x, y z (x,y,z) , 133, :

# for example, Xs enumeration only
for index, (x,y,z) in triples:
  for s in [133 - x ... 0]
    if sums_x[s].cardinalities.length > 0:
      for cardinality in sums_x[s].cardinalities:
        sums_x[s + x].by_index.add( (index,cardinality + 1) ) # this is a set of (index,cardinality) tuples
        sums_x[s + x].cardinalities["cardinality + 1"].push( index ) # hash cardinality to indexes

  sums_x[x].by_index.add( (index,1) )
  sums_x[x].cardinalities["1"].push( index )

, , , . - (, , ) .

:

(1 2 3),(0 4 1),(1 3 4),(1 1 1),(2 1 0)

index = 0
sums_x[1].by_index = {(0,1)} # (index,cardinality)
sums_x[1].cardinalities = {"1": [0]} # cardinality: indexes

index = 1
sums_x[0].by_index = {(1,1)} # (index,cardinality)
sums_x[0].cardinalities = {"0,1": [1]} # cardinality: indexes
sums_x[1].by_index = {(0,1), (1,2)}
sums_x[1].cardinalities = {"1": [0], "2": [1]}

...

index = 4
sums_x[4].by_index = {(4,3), (4,4)} # (index,cardinality)
sums_x[4].cardinalities = {"2": [3], "3": [4], "4": [4]} # cardinality: indexes

sums_y[4].by_index = {(1,1), (3,2), (4,2), (4,3)}
sums_y[4].cardinalities = {"1": [1], "2": [3,4], "3": [4]}

sums_z[4].by_index = {(1,2), (2,1), (3,2), (4,3), (4,2)}
sums_z[4].cardinalities = {"2": [1,3,4], "1": [2], "3": [4]}

, 4 (, ) (4,3), :

sums_z[4]: 4,3 
  => val 0 => lookup by z sum (4 - 0) and cardinality (3 - 1) 
  => sums_z[4].cardinalities[2] yields only one match across: index 3
  => lookup by z sum (4 - 1) and cardinality (2 - 1)
  => sums_z[3].cardinalities[1] yields a match across: index 0
  => possible solution, indexes [4,3,0]
+1

Source: https://habr.com/ru/post/1660223/


All Articles