algorithmdata-structuresdynamic-programmingarray-algorithms

Infected Fish can eat another fish having size less that its own. Minimum number of operation required


An evil scientist has developed an injection that induces insatiable hunger in a fish. On giving this injection, a fish of size x can eat another fish of smaller size y (y < x) and become a fish of size x + y retaining this hunger. An aquarium has a number of fishes of various sizes. The scientist introduces an injected fish into this aquarium with an objective that eventually only 1 fish remains. In order to achieve this, the scientist is allowed only two types of moves: either add a normal fish of any size or remove an existing normal fish from the aquarium. Given the sizes of other fishes in the aquarium and the size of injected fish, write a program to determine the minimum number of moves needed by the scientist to achieve his objective. For example, suppose there are 5 fishes in the aquarium, the injected fish is of size 10 and the other fishes are of sizes 9, 20, 25, and 100. To ensure that only 1 fish remains in the aquarium the scientist needs to remove the fish of size 100 and add a fish of size 3. So the output is 2. The sequence of steps is shown below. The sizes of fishes in the aquarium at each step are shown in curly braces. The highlighted number is the size of the injected fish.

Input format: {infectedFish} # {a,b,c,d ... } where a,b,c etc are normal fishs

Example:

I have used following code to solve the problem.

 public static int count(int inf, int a[], int i, int op){

    //base case
    if(i==a.length){
      return op;
    }

    while(i<a.length && inf>a[i]){
      inf+=a[i];
      i++;
    }

    if(i==a.length){
      return op;
    }

    int curr = inf+inf-1;
    return Math.min(count(curr, a, i, op+1), count(inf, a, i+1, op+1));

  }

Calling it using, System.out.println(count(x, a, 0, 0)); x is infected fish and a is given sorted array;

Is this approach correct? If so, seems like its is having comman subproblem, How can we do memoization?


Solution

  • You can increase the efficiency by slightly modifying your algorithm.

    If you have more than one fish to eat, it is not optimal to remove the next one, and then try to eat a fish which is bigger.

    When you eat a fish, you become bigger, without any cost.

    Therefore, the alternatives are:

    Then, the formula can be simplified as follows, other codes remaining unchanged:

    return Math.min(count(curr, a, i, op+1), op + a.length -1 - i);
    

    In this case, you don't need memoization: the count function is following one way only, always increasing its internal values.

    Note: I assume here that the fishes are sorted, as mentioned in your code.

    Complexity, without taking into account sorting: O(n + log(weight_max/weigth_in))

    EDIT: there is another way to speed up the process:

    If, at a given time, the number of operation op is greater than the current optimum value, then you can stop the recursion.