Tuesday, December 26, 2017

hackerrank ruby unbounded-knapsack

Given some digits 3,4,8 can you make some sum, or how close can you get to that sum. Like 9, or 12, or 133234.

9 is easy: 3+3+3
12 is easy 4+8 or even 3+3+3+3
1234 is not easy.

So, in the beginning it's easy.

So, how do you build up to the bigs?

You start thinking...What's the closest I can get to 1? 2? 3? .... 300? ....1234?

If I can figure out 1, 2, 3....., 300, surely I can get to 1234

because ex. 1234 = 300 + 300 + 300 + 300 + 34
so... the closest sum to 1234 = closest(300) + closest(300) + closest(300) + closest(300) + closest(34)

So the next reasonable question.... Sure, that's one way to get to 1234, but there's also myriad other combinations, so
closest(299) + closest(301) + closest(300) + closest(300) + closest(34)
would HAVE to get us
the SAME result as
closest(300) + closest(300) + closest(300) + closest(300) + closest(34)

We're given these numbers to work with....3,4, and 8
So we know any multiple of 3, 4, and 8
OR
any combination of any multiple of these guys
IS VALID

This mathematical expression expresses that:

3*i + 4*j + 8*k where 0 <= i,j,k <= ~450 ( 3*450 is > 1234 )

Now, let's start building.
What's the closest to 0 with 3,4,8 -> maxSum[0] = 0
1? -> maxSum[1] = 0
2? -> maxSum[2] = 0
3? -> maxSum[3] = 3
4? -> maxSum[4] = 4 
5? -> maxSum[5] = 4
6? -> maxSum[6] = 6 (3+3) 
7? -> maxSum[7] = 7 (3+4)
8? -> maxSum[8] = 8 
9? -> maxSum[9] = 9 (6+3)
10? -> maxSum[10] = 10  (6+4)
11? -> maxSum[11] = 11 (8+3)
12? -> maxSum[12] = 12 (9+3)
etc
etc

"I have to make my new maxSum[n] by adding either 3,4, or 8 (my only options) from a previous maxSum." So what are these "previous" maxSums? Well, they are the maxSums either a distance of 3, 4, or 8 away: maxSum[n-3], maxSum[n-4], or maxSum[n-8]

Which one to use? Well, which one gives you the MAX SUM?!

So, we take the max of:
             maxSum[n-3] + 3 
             maxSum[n-4] + 4
             maxSum[n-8] + 8 

The code in Ruby:

# Enter your code here. Read input from STDIN. Print output to STDOUT
def calculateAnswer(elements, capacity, memArr)
    for weight in 1..capacity do
        for i in 0...elements.length do
            evaluateElement(elements[i], weight, memArr)
        end
    end
    answer = capacity - (memArr.map{|val| capacity - val}.select{|val| val >= 0}.min)
    puts answer
end

def evaluateElement(element, weight, memArray)
    if element <= weight
        memArray[weight] = [memArray[weight],(element + memArray[weight - element])].max
    end
end

t = gets.chomp.to_i
t.times do
    n,expected_sum = gets.strip.split(' ').map(&:to_i)
    list = gets.strip.split(' ').map(&:to_i)
    memArr = Array.new(2001,0)
    calculateAnswer(list, expected_sum, memArr)
end 










No comments:

Post a Comment