pythonalgorithmdata-structurescompiler-errorsglobal-variables

Submission and custom input on GeeksForGeeks gives different judge result on same test case


I was practicing with a GeeksForGeeks problem Fractional Knapsack:

Given weights and values of N items, we need to put these items in a knapsack of capacity W to get the maximum total value in the knapsack.

Note: Unlike 0/1 knapsack, you are allowed to break the item.

Example 1:

Input:

N = 3, W = 50
values[] = {60,100,120}
weight[] = {10,20,30}

Output:

240.00

Explanation

Total maximum value of item we can have is 240.00 from the given capacity of sack.

When I submit my code, the online judge tells me my code returns a wrong answer, however when I run the same test case on custom input, I get the expected answer by the judge.

I searched as to why this happened, and the potential reasons I came across were because of Global/Static variables, however I am not using any global/static variables.

My Approach for the problem was :

The code I am using :

### Item class for reference 
class Item:
    def __init__(self,val,w):
        self.value = val
        self.weight = w
        
class Solution:    
    def fractionalknapsack(self, W,arr,n):
        
        hashmap = {(item.value / item.weight) : item for i,item in enumerate(arr) }
        keys = list(hashmap.keys())
        keys.sort()
        sorted_hashmap = {}
        keys.reverse()
        
        for ele in keys :
            sorted_hashmap[ele] = hashmap[ele]
        
        final_ans = 0
        available_weight = W
        for ratio,item in sorted_hashmap.items() :
            if available_weight > 0 : 
                if item.weight <= available_weight :
                    final_ans += item.value
                    available_weight -= item.weight
                else :
                    final_ans += available_weight * ratio
                    break
            else :
                break
                
                    
        return final_ans

The input for which the test succeeds, but submission fails:

Input :
84 87
78 16 94 36 87 43 50 22 63 28 91 10 64 27 41 27 73 37 12 19 68 30 83 31 63 24 68 36 30 3 23 9 70 18 94 7 12 43 30 24 22 20 85 38 99 25 16 21 14 27 92 31 57 24 63 21 97 32 6 26 85 28 37 6 47 30 14 8 25 46 83 46 15 18 35 15 44 1 88 9 77 29 89 35 4 2 55 50 33 11 77 19 40 13 27 37 95 40 96 21 35 29 68 2 98 3 18 43 53 7 2 31 87 42 66 40 45 20 41 30 32 18 98 22 82 26 10 28 68 7 98 4 87 16 7 34 20 25 29 22 33 30 4 20 71 19 9 16 41 50 97 24 19 46 47 2 22 6 80 39 65 29 42 1 94 1 35 15

Output :
Online Judges Expected Output : 1078.00
My Submission Output : 235.58
My custom input output : 1078.00

Solution

  • This is indeed very confusing! I looked at the Python version that GeeksForGeeks is running your code on, and at the time of writing these versions are different depending on whether you test or submit!

    This explains why you get different results when testing versus submitting. Since Python 3.6 dictionaries are iterated in insertion order, but in older versions the iteration order is undefined -- there is no guarantee whatsoever that the order in which you inserted the items will also be the order in which the items are iterated.

    Taking a step back, you should not need a dictionary here. In fact, it will be problematic when two items happen to have the same ratio, because then you will lose out on one.

    Solve this by just sorting the input items by the ratio. Here is your code with the hasmap removed, and the sort called on the input list instead:

    class Solution:
        def fractionalknapsack(self, W, arr, n):
            arr.sort(key=lambda item: item.value / item.weight, reverse=True)
            final_ans = 0
            available_weight = W
            for item in arr:
                if available_weight > 0: 
                    if item.weight <= available_weight:
                        final_ans += item.value
                        available_weight -= item.weight
                    else :
                        final_ans += available_weight * item.value / item.weight
                        break
                else:
                    break
            return final_ans