Calculate increments so that 2 numbers become equal

Asked

Viewed 214 times

4

The problem:

With a very creative name, the Protagonist is in his first episode of its incredible saga!

In an afternoon any Z, the Protagonist’s best friend, challenged the even for a super fun challenge.

Z writes two whole numbers A and B on a white board and asks if the Protagonist can make the two integers equal using the minimum number of moves.

In a movement, the Protagonist can make one of the following actions:

  1. Choose one of the numbers and add 3 to it (x = x + 3).

  2. Choose one of the numbers and add 2 to it (x = x + 2).

Knowing this, as the Protagonist knows that you are very good he asked so that you could help him on this mission and tell him how many minimum of moves he needs to make both of them numbers become equal. You receive two integers (1 <= A, B <= 10 5). A single integer N, equivalent to quantity, shall be printed minimum of movements the Protagonist needs to make.

My attempt: The entry there is standard of the question because it informs the two numbers on the same line, I created a list already adding them converted to integers pq they were previously strings.
I used the function max() and min() to take the respective values (higher and lower).
The variables are named because it was still testing, c1 and c2 are the counters of the sum movements that I make in the smallest number, a and b are two temporary variables that I created to take the value of the smallest number.

Then I try to create a list of numbers by jumping from 2/3 until I reach the highest number, incrementing the counter every time. At the end I compare which counter is smaller, because it would be the final answer, the first if, was like this because in some cases the counter of both was equal ex: when the input was 6 and 8.

inserir a descrição da imagem aqui

entrada = str(input()).split()

numeros = []

for i in entrada:
    numeros.append(int(i))

B = max(numeros)
A = min(numeros)
 
div, mod = divmod(B-A, 3)
if mod != 0:
    div += 3 - mod
 
print(f'{div}')
  • 1

    Could you describe in text what logic you tried to implement?

  • 1

    Nice and easy, you’re missing the point. You get two numbers, in the smallest you go the sum of three in three, in the largest you go adding two in two. You want to know how many sums will be needed for the values to be equal?

  • 1

    You can put all this directly in the question to [Edit]. Better than leaving it in the comments.

  • @Augustovasques, I’m getting two numbers, so I got a bigger one and a smaller one. the character in the question has two options: add 3 to the number or add 2 to the number until they are equal (highest and lowest number of the input)

  • @Woss all right.

  • 1

    @Augustovasques later I have to say which is the smallest movement I make to match the numbers (using 3 or 2)

  • 1

    Now it’s clear, I’m just gonna shake it up a little bit to make it easier to read.

  • Taking advantage, input already returns a string, so do str(input()) is unnecessary. And if you are already absolutely sure that there will always be 2 numbers on the same line, you can do: a, b = map(int, input().split())

  • John, I reversed your last issue because it’s important that the question has the code you tried. Learn more at: https://pt.meta.stackoverflow.com/a/5484/112052

Show 4 more comments

3 answers

6


Complementing the another answer (that as the author himself acknowledged, in some cases may fail), follows a small adjustment.

The idea remains the same: we take the difference between the numbers and divide by 3 (let’s call the result of this division n).

If the division is exact (i.e., if the rest is zero), this means that a is exactly n increments of 3 b. So far, it’s the same reasoning as the other answer.

If the rest of the division is 2, then just make one more increment of 2 (that is, it remains the same as the other answer):

a  | a + 3 | a + 6 ... | a + 3n |   2   b
   <---------------------------->   ^
        n incrementos de 3          |
                                    \_ 1 incremento de 2

Total: n + 1 incrementos

But what if the rest of the division is 1? That means we have the following:

a  | a + 3 | a + 6 ... | a + 3n |   1   b
   <---------------------------->
        n incrementos de 3        + 1

At first, one more 3-in-1 a and an increment of 2 in b (that was suggested in the other answer), totaling n + 2 increments. But you can actually do it like this:

  • instead of n increments of 3, we make n - 1 increments of 3. With this, there will still be 4 to reach b
  • then we make 2 increments of 2
a  | a + 3 | a + 6 ... | a + 3(n - 1) |   4     b
   <---------------------------------->   ^
        n - 1 incrementos de 3            |
                                          \_  2 incrementos de 2, totalizando os 4 que faltam

Total: n + 1 incrementos

In total, we will have n - 1 increments of 3, and 2 increments of 2, totaling n + 1 increments.


I mean, it would all come down to:

  • divide b - a by 3
  • if the division is accurate, the result of the division is the answer
  • if not accurate, sum 1 to the result of the

But it’s still not enough

If the difference between a and b is less than 3, the value of n is equal to zero, so we can not apply the above rule, because we have no way n - 1 increments of 3 (as this would give "-1 increments").

So in this particular case we have:

  • if the rest is 1, it would have to be 2 increments (1 of 3 in a and 1 of 2 in b)
  • if the rest is 2, it would have to be 1 increment of 2 in a
  • if the rest is zero, it is because a and b are equal, so you need zero increments

Put it all together, it’d be like this:

# ler os valores de "a" e "b"...

qtd, resto = divmod(b - a, 3)
if resto != 0:
    if qtd == 0: # quando a diferença entre a e b é menor que 3
        qtd = 3 - resto
    else:
        qtd += 1
print(f'Foram necessários {qtd} movimentos')

And taking advantage, if you know that the input will always have 2 numbers on the same line and nothing else, you can read them like this:

a, b = map(int, input().split())

And if they are not necessarily in order (for example, if the a may be greater than the b input), can calculate the difference using abs, to return the value without signal:

qtd, resto = divmod(abs(b - a), 3)

This way you don’t have to worry about creating a list with the numbers, to then catch the max and the min.

Or even, as there are only 2 numbers, it would be enough to invert them if the a is greater:

a, b = map(int, input().split())
if a > b:
    a, b = b, a
qtd, resto = divmod(b - a, 3)
etc...

5

The solution presented in this answer does not work for all situations.

I will not analyze your code because you misunderstood the problem and the code does not reflect what is asked in the exercise.

Whereas you have the numbers A and B (B > A).

With each "move" you can decide whether you want to increment by 2 or 3 any of the numbers, until they are numerically equal. For example, considering that A=2 and B=13, we need to go out from 2 to 13.

  1. We can add 3 in A, getting A=5;
  2. We can add 3 in A, getting A=8;
  3. We can add 3 in A, getting A=11;
  4. We can add 2 in A, getting A=13;

Therefore, 4 "movements" were necessary. But what if A=2 and B=12?

  1. We can add 3 in A, getting A=5;
  2. We can add 3 in A, getting A=8;
  3. We can add 3 in A, getting A=11;
  4. We can add 2 in B, getting B=14;
  5. We can add 3 in A, getting A=14;

We now need 5 "moves".

The logic is simplified in:

  • While the B-A difference is greater than or equal to 3, increment A by 3;
  • If difference B-A is equal to 2, increment A by 2;
  • If the difference B-A is 1, increment B by 2;

In code, it would look something like:

quantidade = 0

while (B-A > 0):
  quantidade += 1
  if B-A >= 3:
    A += 3
  elif B-A == 2:
    A += 2
  else:
    B += 2

print(f'Foram necessários {quantidade} movimentos')

Or else:

quantidade = 0

while (B-A >= 3):
  quantidade += 1
  A += 3

if B-A == 2:
  A += 2
  quantidade += 1
elif B-A == 1:
  B += 2
  A += 3
  quantidade += 2

print(f'Foram necessários {quantidade} movimentos')

This solution is not ideal, although it is simpler to understand, because its computational complexity is O(n), in which the number of operations performed will be directly dependent on the input. For B >> A, there will be performance impact.

Mathematics

You don’t need a loop to know how many times you will increment the value of A by 3 until it approaches B. Mathematics already tells you this in an operation.

  • If the B-A value is multiple of 3, you will need (B-A)//3 moves - only increments of 3 in A;
  • If the rest of the division of B-A by 3 is 2, you will need (B-A)//3 + 1 moves - several increments of 3 and one of 2 in A;
  • If the rest of the division of B-A by 3 is 1, you will need (B-A)//3 + 2 moves - several increments of 3 in A, an increment of 2 in A and an increment of 2 in B;

Understand // as an entire division between the operands.

Therefore:

quantidade = 0

if (B-A) % 3 == 0:
  quantidade = (B-A) // 3
elif (B-A) % 3 == 1:
  quantidade = (B-A) // 3 + 2
else:
  quantidade = (B-A) // 3 + 1

print(f'Foram necessários {quantidade} movimentos')

This solution is ideal, even though it initially seems more complex, since its computational complexity is O(1), performing exactly the same number of operations, regardless of the input. The impact on B >> A will be the same as when B is very close to A.

Mathematics v2.0.0

Thanks to the collaboration of @hkotsubo in the comments reminding of the function divmod, it is still possible to do:

A = 2
B = 13

div, mod = divmod(B-A, 3)

if mod == 2:
    mod = 1
elif mod == 1:
    mod = 2

print(f'Foram necessários {div+mod} movimentos')
  • 1

    Please avoid long discussions in the comments; your talk was moved to the chat

  • Many thanks @hkotsubo

1

Just a small rewrite (of obfuscated and dubious taste) of the @hkotsubo version, in order to decompress a boring job I have to do...

a,b = sorted(map(int,input().split()))
q,r = divmod(b-a,3)
print( q + (r!=0) + (b-a==1))

Browser other questions tagged

You are not signed in. Login or sign up in order to post.