Приведение пары целых чисел к равенству


51

Это было вдохновлено математической проблемой, которую я видел где-то в Интернете, но не помню, где (ОБНОВЛЕНИЕ: оригинальная проблема была найдена в subreddit математических загадок с доказательством при условии, что это возможно, также см. Этот пост Math SE ), прося доказательство того, что следующий процесс возможен для любой произвольной пары целых чисел (насколько я помню, это было возможно для любой данной пары):

Для пары целых чисел j и k удвоьте одно из них и добавьте одно к другому, в результате чего получится пара новых целых чисел, т. Е. (J, k) -> (j + 1, k * 2) или (j * 2, к + 1). Затем повторите этот процесс с этими целыми числами с целью получения равных пары целых чисел.

Эти приведенные примеры не обязательно являются оптимальными, но показывают, как этот процесс может быть выполнен для любых целых чисел, положительных, отрицательных или нулевых:

(2, 5) -> (3, 10) -> (6, 11) -> (12, 12)

(5, 6) -> (6, 12) -> (7, 24) -> (14, 25) -> (28, 26) -> (56, 27) -> (112, 28) -> (113, 56) -> (226, 57) -> (227, 114) -> (228, 228)

(0, 2) -> (1, 4) -> (2, 5) -> (3, 10) -> (6, 11) -> (12, 12)

(-4, 0) -> (-3, 0) -> (-2, 0) -> (-1, 0) -> (0, 0)

(3, -1) -> (6, 0) -> (12, 1) -> (13, 2) -> (14, 4) -> (15, 8) -> (16, 16)

(-4, -3) -> (-8, -2) -> (-16, -1) -> (-32, 0) -> (-31, 0) -> ... -> (0, 0)

Вызов

Создайте программу, которая дает два целых числа, выводит список шагов, необходимых для того, чтобы сделать эти числа равными, многократно увеличивая одно и удваивая другое

Характеристики

  • Решение не обязательно должно быть оптимальным, но оно должно решать конечное число шагов для любой произвольной пары
  • Ввод должен быть двух целых

  • Выходными данными могут быть любые разумные выходные данные, которые четко обозначают результирующие целые числа каждого шага, например:

    • строка с двумя различными разделителями (любой символ, пробел и т. д.), один для каждого целого числа в паре и один для каждой пары
      • например, вход j, k: 2, 5 -> выход: 3,10; 6,11; 12,12
    • список списков целых чисел
      • например, вход j, k: 2, 5 -> выход: [[3, 10], [6, 11], [12, 12]]
  • Если вход представляет собой пару равных чисел, вы можете вывести что угодно, если это согласуется с другими нетривиальными ответами

    • например
      • если вход [2, 5] имеет выход [[3, 10], [6, 11], [12, 12]], который не включает входную пару, то вход [4, 4] ничего не должен выводить.
      • если вход [2, 5] имеет выход [[2, 5], [3, 10], [6, 11], [12, 12]], который включает входную пару, то вход [4, 4] должен вывод [[4, 4]].
  • Применяются стандартные методы ввода-вывода и запрещаются стандартные лазейки

  • Это код гольф, поэтому самый короткий ответ в байтах выигрывает


13
Кстати, это хороший первый вызов. Добро пожаловать в PPCG!
Арно

@ Arnauld Спасибо! Также спасибо за указание на ошибку, я сделал все примеры вручную и действительно должен сначала реализовать решение
JMigst

Может ли вывод быть обратным? Например, [(12,12),(6,11),(3,10),(2,5)]для ввода (2,5)?
Лайкони

1
@Laikoni Учитывая, что все необходимые шаги все еще выводятся, я думаю, что это нормально
JMigst

1
Я добавил это в OEIS как A304027 . Пара (34,23) кажется особенно сложной.
Питер Кейджи

Ответы:


10

JavaScript (ES6), 111 90 83 байта

f=(a,b,p=q=[],u=[...p,[a,b]])=>a-b?f(...(q=[[a*2,b+1,u],[a+1,b*2,u],...q]).pop()):u

Попробуйте онлайн!

комментарии

f = (                       // f = recursive function taking:
  a, b,                     //   (a, b) = input integers
  p =                       //   p[] = current path
  q = [],                   //   q[] = queue
  u = [...p, [a, b]]        //   u[] = updated path with [a, b] appended to it
) =>                        //
  a - b ?                   // if a is not yet equal to b:
    f(...                   //   recursive call, using spread syntax:
      (q = [                //     prepend the next 2 possible moves in the queue:
        [a * 2, b + 1, u],  //       a * 2, b + 1
        [a + 1, b * 2, u],  //       a + 1, b * 2
        ...q                //
      ]).pop()              //     use the move on the top of the queue
    )                       //   end of recursive call
  :                         // else:
    u                       //   success: return the (updated) path

9

Haskell, 70 69 байтов

f(w@((i,j):_):r)|i==j=w|1<2=f$r++[(i+1,j*2):w,(i*2,j+1):w]
g x=f[[x]]

Попробуйте онлайн!

Простая БФС. Отслеживает шаги в списке из списка пар.

g x=f[[x]]                -- start with a single list where the only
                          -- step is the starting pair
f (w@((i,j):_):r) =       -- let w be the first list of steps
                          --     (i,j) the last pair of the first list of steps
                                       ('last' as in last operated on. As we store
                                        the steps in reverse order it's the
                                        first element in the list)
                          --     r all other lists of steps
   i==j=w                 -- if i==j stop and return the first list
   1<2= f                 -- else make a recursive call
          r++             -- where the new input list is r followed by
                          -- the first list extended one time by
          [(i+1,j*2):w,         (i+1,j*2) and one time by
             (i*2,j+1):w]       (i*2,j+1)

7

Python 3 , 90 74 72 байта

-2 байта благодаря Денису .

def f(a,*x):j,k=a[0];return(j==k)*a or f(*x,[(2*j,k+1)]+a,[(j+1,2*k)]+a)

Попробуйте онлайн!

Принимает ввод в виде одноэлементного списка .


Ungolfed

def f(a,*x):              # function taking at least one argument
                          # a is the first argument, all other are stored in x
  j, k = a[0]             # get the newest values of the current path
  return (j==k)*a         # if j is equal to k return the current path
                  or      # else ...
   f(                     # continue ...
     *x,                  # with the remaining paths ...
     [(2*j,k+1)]+a        # and split the current path ...
     [(j+1,2*k)]+a        # in two new ones
    ) 

4

Pyth, 41 байт

J]]QL,hhb*2ebWt{KehJ=J+tJm+hJ]d,yK_y_K)hJ

Попробуй здесь

объяснение

Это довольно простой поиск в ширину. Сохраняйте очередь возможных последовательностей ( J), и пока мы не получим подходящую пару, возьмем следующую последовательность, закрепим каждый из возможных ходов и поместим их в конец очереди.
Для краткости мы определяем функцию y(используя лямбда-выражение L) для выполнения одного из шагов и применяем ее как вперед, так и назад.



4

05AB1E , 25 22 20 байт

Принимает дважды вложенный список в качестве входных данных и выводит зубчатый список с каждым шагом на одну глубину вложения.

[ć¤Ë#¤xs>R‚ø`R‚s¸sâ«

Попробуйте онлайн!

объяснение

[                      # start a loop
 ć                     # extract the first element of the current list (current path)
  ¤Ë#                  # break if all elements in the head are equal
     ¤xs>              # duplicate one copy of the head and increment another
         R             # reverse the incremented copy
          ‚ø           # zip them together
            `R‚        # reverse the tail of the zipped list
               s¸sâ    # cartesian product with the rest of the current path
                   «   # append to the list of all current paths

4

Сетчатка , 72 байта

\d+
*
/\b(_+),\1\b/^+%`(_+),(_+)$
$&;_$&$2¶$=;$1$&_
G`\b(_+),\1\b
_+
$.&

Попробуйте онлайн! Всего два теста из-за ограничений унарной арифметики. Объяснение:

\d+
*

Преобразовать в одинарный.

/\b(_+),\1\b/^+

Пока на входе нет пары идентичных чисел ...

%`(_+),(_+)%

... соответствует последней паре в каждой строке ...

$&;_$&$2¶$=;$1$&_

... и превратить строку в две строки, одна с суффиксом с увеличением первого числа, вторая с удвоением, другая с суффиксом первого числа, удвоенного и второго с увеличением.

G`\b(_+),\1\b

Держите линию с соответствующей парой.

_+
$.&

Конвертировать обратно в десятичную. 89 88-байтовая десятичная арифметическая версия без знака (работает также с 0):

/\b(\d+),\1\b/^+%`(\d+),(\d+)$
$&;$.(_$1*),$.(2*$2*)¶$=;$.(2*$1*),$.(_$2*
G`\b(\d+),\1\b

Попробуйте онлайн!


4

MATL , 24 байта

`vxG1r/q:"tt1rEk(+]td0=~

Время выполнения является случайным, но оно конечно с вероятностью 1.

Код очень неэффективен. Входы, требующие более 4 или 5 шагов, имеют большую вероятность истечения времени ожидания в онлайн-переводчике.

Попробуйте онлайн!

объяснение

`         % Do...while
  vx      %   Concatenate stack and delete. This clears the stack from contents
          %   of previous iterations   
  G       %   Push input
  1       %   Push 1
  r       %   Push random number uniformly distributed on (0,1)
  /       %   Divide
  q       %   Subtract 1. The result is a random number, t, that has nonzero
          %   probability of being arbitrarily large. Specifically, t is in
          %   the interval (0,1) with probability 1/2; in (1,2) with probability
          %   1/6; ... in (k,k+1) with probability 1/((k+1)*(k+2).
  :       %   Range [1 2 ... floor(t)]
  "       %   For each (that is: do thw following floor(t) times)
    tt    %     Duplicate twice
    1     %     Push 1
    rEk   %     Random number in (0,1), times 2, round down. This produces a 
          %     number i that equals 0 or 1 with probability 1/2
    (     %     Write 1 at entry i. So if the top of the stack is [a b], this
          %     transforms it into either [1 b] or [a 1]
    +     %     Add, element-wise. This gives either [a+1 2*b] or [2*a b+1] 
  ]       %   End for each
  td      %   Duplicate, consecutive difference between the two entries
  0=~     %   Is it not zero? If so, the do...while loop continues with a new
          %   iteration. Normally the code 0=~ could be omitted, because a
          %   nonzero consecutive difference is truthy. But for large t the
          %   numbers a, b may have gone to infinity, and then the consecutive
          %   difference gives NaN
          % End do...while (implicit). Display (implicit)

3

Stax , 29 26 байт

ä⌠|Tô&cm♂NV↓↔╗╣¢♠╜╒█¡Φ≈ñY@

Запустите и отладьте его

Это поиск в ширину. Это кажется достаточно быстрым.

Требуется пара целых чисел с двойным массивом. Результатом является разделенный пробелами список значений. Каждые два значения представляют одну пару на пути к решению.



2

Красный , 142 байта

Принимает входные данные как дважды вложенный блок пары целых чисел в формате Red(2, 5) ->2x5

Например, возвращает результат в виде списка красных пар 2x5 3x10 6x11 12x12. Включает начальную пару.

func[c][a: copy[]foreach d c[l: last d if l/1 = l/2[return d]do replace/all{%+ 1x0 * 1x2
%* 2x1 + 0x1}"%""append/only a append copy d l "]f a]

Попробуйте онлайн!

Строгий ввод:

Ввод двух чисел, например 2 5

Красный , 214 байт

func[a b][g: func[c][a: copy[]foreach d c[l: last d if l/1 = l/2[return d]append/only a append copy d l + 1x0 * 1x2
append/only a append copy d l * 2x1 + 0x1]g a]c: copy[]insert/only c reduce[do rejoin[a 'x b]]g c]

Попробуйте онлайн!

Объяснение:

f: func[a b][                 
g: func[c][                                   ; recursive helper function
  a: copy[]                                   ; an empty block
  foreach d c[                                ; for each block of the input 
    l: last d                                 ; take the last pair
    if l/1 = l/2[return d]                    ; if the numbers are equal, return the block 
    append/only a append copy d l + 1x0 * 1x2 ; in place of each block append two blocks
    append/only a append copy d l * 2x1 + 0x1 ; (j+1, k*2) and (j*2, k+1)
  ]                                           ; using Red's arithmetic on pairs
  g a                                         ; calls the function anew
]
c: copy[]insert/only c reduce[do rejoin[a 'x b]]; prepares a nested block from the input
g c                                           ; calls the recursive function 
]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.