How to compute minimum number of operation required to make all the elements of sequence equal to each other

Viewed 3498
The problem is from a programming competition.

You are given two sequences A (a1, a2, a3, ... an) and B (b1, b2, b3, ... bn) of the same length N. In each step you can set ai = ai - bi if ai >= bi. Determine the minimum number of steps required to make all the numbers in A equal to each other.

For Example

A = {5, 7, 10, 5, 15} 
B = {2, 2, 1, 3, 5}

In the above example, the minimum number of steps required to make all the elements in A equal to each other is 8.

A = {5, 15, 25, 35, 45, 90, 100}
B = {5, 5, 5, 5, 5, 5, 5}

In the above example, the minimum number of steps required to make all the elements in A equal to each other is 56.

Do note that if it is not possible to make all the elements of the sequence A equal to each other then print -1.

For Example

A = {5, 6}  
B = {4, 3}

In the above case, the answer is -1 because it is impossible to make all the elements of A equal to each other.

A = {5, 15, 25, 35, 45, 90, 100}
B = {5, 5, 5, 5, 5, 0, 5}

In the above case, the answer is -1 because it is impossible to make all the elements of A equal to each other.

Could anyone can help me out on how to solve this problem efficiently?

2 Answers

The way I see it there are two ways to solve it.

  1. Iterative algorithm with some logic (Which I will implement in Python)
  2. You can use sets (feels like kind of cheating).

The way the author probably meant you to do:

Every time we will try to reach the minimal value of the list (or lower) with all the other items in the list. If all the items are the same we stop and return success, otherwise we keep going. If some of the items fall below 0 we stop.

import math

num_of_nums = int(input())

a_s = list(map(int, input().split()))
b_s = list(map(int, input().split()))

operations = 0
m = min(a_s)
while not all([a_s[0] == tmp for tmp in a_s]):
    if m < 0:
        print(-1)
        exit(0)
    for i, (a, b) in enumerate(zip(a_s, b_s)):
        if b == 0 and m != a:
            print(-1)
            exit(0)
        elif b == 0 and m == a:
            continue

        operations_to_min = int(math.ceil((a - m) / b))
        operations += operations_to_min
        a_s[i] = a - operations_to_min * b
    m = min(a_s)
print(operations)

The sets way:

After reading the inputs we create a set of numbers that can be created from reducing each b from a, so for the example provided we get:

[{1, 3, 5}, {1, 3, 5, 7},...

Now we find the intersection set, and take the highest number from it.
After this number is found we count the number of operations to reach that number for each a and b pair.

import functools
num_of_nums = int(input())

a_s = list(map(int, input().split()))
b_s = list(map(int, input().split()))

sets = [set([a - b * i for i in range(a // b + 1 if b > 0 else 1)]) for a, b in zip(a_s, b_s)]
res = functools.reduce(lambda a, b: a & b, sets)

if len(res) > 0:
    biggest_num = max(res)
    operations = 0
    for a, b in zip(a_s, b_s):
        if b > 0:
            operations += (a - biggest_num) // b
    print(operations)
else:
    print(-1)

The target cannot be greater than the smallest element in A. If m is the index of the smallest element in A, the target must also be one of the values A[m] - k * B[m] (non-negative integer k). Since there may be duplicates of the smallest element in A, each with a different b, to simplify, we can just try all targets equal or smaller than min(A).

We try them in a descending loop since clearly the highest valid one would take the least steps to reach. The check for validity, which must apply to all (a, b) pairs, given candidate target t:

(a - t) mod b == 0

Example:

A = {5, 7, 10, 5, 15}
B = {2, 2, 1, 3, 5}

t = 5

a's:

 5: 5 == 5
 7: (7 - 5) mod 2 == 0
10: (10 - 5) mod 1 == 0
 5: 5 == 5
15: (15 - 5) mod 5 == 0

JavaScript code:

function f(A, B){
  const n = A.length;
  const m = Math.min(...A);
  let result;
  
  for (let t=m; t>=0; t--){
    result = 0;
    
    for (let i=0; i<n; i++){
      if ((A[i] - t) % B[i] == 0){
        result = result + (A[i] - t) / B[i];
        
      } else {
        result = -1;
        break;
      }
    }
    
    if (result > -1)
      return result;
  }
  
  return result;
}

var ABs = [
  [[5, 7, 10, 5, 15],
   [2, 2, 1, 3, 5]],

  [[5, 6],
   [4, 3]]
];

for (let [A, B] of ABs){
  console.log(`A: ${ A }`);
  console.log(`B: ${ B }`);
  console.log(f(A, B));
  console.log('');
}

Related