-5

Maximum Value of the Loot

Problem Introduction:

A thief finds much more loot than his bag can fit. Help him to find the most valuable combination of items assuming that any fraction of a loot item can be put into his bag. Problem Description

Task: The goal of this code problem is to implement an algorithm for the fractional knapsack problem.
Input Format: The first line of the input contains the number of items and the capacity of a knapsack. The next lines define the values and weights of the items. The -th line contains integers and —the value and the weight of -th item, respectively.
Constraints: 1≤≤103,0≤ ≤2·106;0≤ ≤2·106,0< ≤2·106 for all 1≤≤.All the numbers are integers.
Output Format Output the maximal value of fractions of items that fit into the knapsack. The absolute value of the difference between the answer of your program and the optimal value should be at most −3 your answer, while being computed correctly, can turn out to be wrong because of rounding issues).

Sample 1.

Input:
3 50
60 20
100 50
120 30

Output:
180.0000
To achieve the value 180, we take the first item and the third item into the bag.

Sample 2.

Input:
1 10
500 30
Output:
166.6667

My code:

# Maximum Value of the Loot

def knapsack(n, capacity, value_list, weight_list):
    unitValues_list = []
    
    #First lets calculate the unitValues_list
    for i in range (n):
        unitValue = (value_list[i]/weight_list[i])
        unitValues_list.append(unitValue)
    
    #Now lets fill the knapsack, intake is how much is in the bag at the moment!
    intake = 0
    max_value = 0
    factor = True

    while(factor):
        max_index = unitValues_list.index(max(unitValues_list, default=0)) 
        # this gives the index of the max valued element
        
        if(weight_list[max_index] <= capacity):
            # In this case, full item is taken in
            intake = weight_list[max_index]
            capacity -= weight_list[max_index]
            max_value += value_list[max_index]
            
        else:
            # weight_list[max_index] > capacity
            # In this case, fraction to be taken
            intake += capacity
            capacity = 0
            max_value += unitValues_list[max_index]*intake
            
        weight_list.pop(max_index)
        value_list.pop(max_index)
        unitValues_list.pop(max_index)
        print(weight_list)

        n -= 1 #no. of items left
        factor = ((n != 0) if ((capacity != 0) if True else False) else False)

    return max_value

if __name__ == "__main__":
    value_list = []
    weight_list = []
    
    #The first line of the input contains the number  of items and the capacity  of a knapsack. 
    #The next  lines define the values and weights of the items. 
    
    n , capacity = map(int, input().split())
    
    for i in range (n):
        value , weight = map(int, input().split())
        value_list.append(value)
        weight_list.append(weight)
        
    #Output the maximal value of fractions of items that fit into the knapsack.
    print("{:.10f}".format(knapsack(n, capacity, value_list, weight_list)))

I keep getting an error:

Failed case #6/13: Wrong answer
got: 8740.3008948546 expected: 7777.731
(Time used: 0.00/5.00, memory used: 9191424/671088640.)

Community
  • 1
  • 1
Delicia Fernandes
  • 582
  • 12
  • 19

2 Answers2

1

Correcting Wrong Answer

Corrected fraction to be taken by changing

intake += capacity
capacity = 0
max_value += unitValues_list[max_index]*intake

To

fraction = capacity / weight_list[max_index] 
max_value += value_list[max_index]*fraction
capacity = 0 

Refactored Code

def knapsack(n, capacity, value_list, weight_list):
    unitValues_list = []

    #First lets calculate the unitValues_list
    for i in range (n):
        unitValue = (value_list[i]/weight_list[i])
        unitValues_list.append(unitValue)

    #Now lets fill the knapsack, intake is how much is in the bag at the moment!
    intake = 0
    max_value = 0
    factor = True

    while(factor):
        max_index = unitValues_list.index(max(unitValues_list, default=0)) 
        # this gives the index of the max valued element

        if(weight_list[max_index] <= capacity):
            # In this case, full item is taken in
            intake = weight_list[max_index]
            capacity -= weight_list[max_index]
            max_value += value_list[max_index]

        else:
            # weight_list[max_index] > capacity
            # In this case, fraction to be taken
            fraction = capacity / weight_list[max_index] 
            max_value += value_list[max_index]*fraction
            capacity = int(capacity - (weight_list[max_index] * fraction))

        weight_list.pop(max_index)
        value_list.pop(max_index)
        unitValues_list.pop(max_index)
        print(weight_list)

        n -= 1 #no. of items left
        factor = ((n != 0) if ((capacity != 0) if True else False) else False)

    return max_value

if __name__ == "__main__":
    value_list = []
    weight_list = []

    #The first line of the input contains the number  of items and the capacity  of a knapsack. 
    #The next  lines define the values and weights of the items. 

    n , capacity = map(int, input('n, capacity: ').split())

    for i in range (n):
        value , weight = map(int, input('value, weight: ').split())
        value_list.append(value)
        weight_list.append(weight)

    #Output the maximal value of fractions of items that fit into the knapsack.
    print("{:.10f}".format(knapsack(n, capacity, value_list, weight_list)))

Note

Time was not mentioned as an issue.

Complexity can be changed from current O(n^2) algorithm to O(n*log(n)) by sorting unitValues_list rather than computing max each time.

DarrylG
  • 16,732
  • 2
  • 17
  • 23
1

Here's the solution for the loot problem. Following the greedy algorithm we start filling from the item with highest unit price..

def loot(t_weight,cost, unit,weight):
    count = 0
    while t_weight!=0:
        c_cost = max(unit)
        act_ind = unit.index(c_cost)
        c_weight=weight[act_ind]
        print(c_cost,c_weight,act_ind)
        if c_weight >= t_weight:
            count+=t_weight*c_cost
            t_weight = 0
        elif c_weight<t_weight:
            t_weight-=c_weight
            count+=(c_weight)*c_cost
            cost.pop(act_ind)
            unit.pop(act_ind)
            weight.pop(act_ind)
            print()
    return count
    
    
def main():
    g1=str(input())
    item,cap = map(int,g1.split())
    dict={}
    cost=[]
    weight=[]
    unit =[]
    for i in range(1,item+1):
        g2=str(input())
        a,b = map(int,g2.split())
        cost.append(a)
        weight.append(b)
        j = (cost[i-1])/weight[i-1]
        unit.append(j)
    print(loot(cap,cost,unit,weight))
main()