Приведення пари цілих чисел до рівності


51

Це надихнуло математичну проблему, яку я бачив десь в Інтернеті, але не пам’ятаю, де (ОНОВЛЕННЯ: Оригінальна проблема була знайдена в математичних загадках subreddit із підтвердженням того, що це можливо, також дивіться цей Math SE post ), запитуючи доказ того, що наступний процес можливий для будь-якої довільної пари цілих чисел (з того, що я пам’ятаю, це було можливим для будь-якої заданої пари):

Давши пару цілих чисел, j і k, подвійно одне з них і додайте одне до іншого, в результаті виходить пара нових цілих чисел, тобто (j, k) -> (j + 1, k * 2) або (j * 2, k + 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
Це хороший перший виклик, BTW. Ласкаво просимо до 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]]

Спробуйте в Інтернеті!

Простий BFS. Слідкує за кроками у списку списку пар.

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)

Спробуйте в Інтернеті!

Вводить введення як однотонний список .


Безумовно

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

Стакс , 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.