Trazendo um par de números inteiros à igualdade

51

Isso foi inspirado por um problema de matemática que vi em algum lugar na internet, mas não me lembro onde (UPDATE: O problema original foi encontrado no subreddit de enigmas matemáticos com uma prova, desde que seja possível, veja também este post do Math SE ), solicitando uma prova se o seguinte processo é possível para qualquer par arbitrário de números inteiros (pelo que me lembro, era possível para qualquer par):

Dado um par de números inteiros, j e k, dobre um deles e adicione um ao outro, resultando em um par de novos números inteiros, ou seja, (j, k) -> (j + 1, k * 2) ou (j * 2, k + 1). Em seguida, repita esse processo com esses números inteiros, com o objetivo de ter o par de números inteiros igual.

Estes exemplos fornecidos não são necessariamente ótimos, mas mostram como esse processo pode ser feito em números inteiros, positivos, negativos ou zero:

(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)

Desafio

Crie um programa que, com dois números inteiros, produza a lista de etapas necessárias para tornar esses inteiros iguais incrementando repetidamente um e dobrando o outro

Especificações

  • A solução não precisa ser ideal, mas deve resolver em um número finito de etapas para qualquer par arbitrário
  • A entrada deve ter dois números inteiros

  • Saída pode ser qualquer saída razoável que denota claramente os números inteiros resultantes de cada etapa, por exemplo:

    • uma string com dois delimitadores distintos (qualquer símbolo, espaço em branco etc.), um para cada número inteiro em um par e um para cada par
      • por exemplo, entrada j, k: 2, 5 -> saída: 3,10; 6,11; 12,12
    • uma lista de listas de números inteiros
      • por exemplo, entrada j, k: 2, 5 -> saída: [[3, 10], [6, 11], [12, 12]]
  • Se a entrada for um par de números iguais, você poderá produzir qualquer coisa, desde que seja consistente com outras respostas não triviais

    • por exemplo
      • se a entrada [2, 5] tiver saída [[3, 10], [6, 11], [12, 12]], que não inclui o par de entrada, a entrada [4, 4] não deve produzir nada.
      • se a entrada [2, 5] tiver saída [[2, 5], [3, 10], [6, 11], [12, 12]], que inclui o par de entrada, a entrada [4, 4] deve saída [[4, 4]].
  • Os métodos de IO padrão se aplicam e as brechas padrão são proibidas

  • Este é o código de golfe, então a resposta mais curta em bytes ganha

JMigst
fonte
13
Este é um bom primeiro desafio, BTW. Bem-vindo ao PPCG!
Arnauld
@Arnauld Obrigado! Também obrigado por apontar o fora de erro, eu fiz todos os exemplos de mão e realmente deve implementar uma solução de me primeiro
JMigst
A saída pode estar no sentido inverso? Por exemplo, [(12,12),(6,11),(3,10),(2,5)]para entrada (2,5)?
Laikoni
11
@Laikoni Considerando todos os passos necessários ainda são emitidas, eu acho que é bom
JMigst
11
Adicionei isso ao OEIS como A304027 . O par (34,23) parece ser especialmente difícil.
Peter Kagey 5/05

Respostas:

10

JavaScript (ES6), 111 90 83 bytes

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

Experimente online!

Comentado

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
Arnauld
fonte
9

Haskell, 70 69 bytes

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]]

Experimente online!

Um simples BFS. Mantém o controle das etapas em uma lista de lista de pares.

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)
nimi
fonte
7

Python 3 , 90 74 72 bytes

-2 bytes graças a Dennis .

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)

Experimente online!

Recebe entrada como uma lista de singleton .


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
    ) 
ovs
fonte
4

Pitão, 41 bytes

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

Experimente aqui

Explicação

Essa é a primeira pesquisa bastante direta. Mantenha uma fila de possíveis sequências ( J) e, até obtermos um par correspondente, faça a próxima sequência, prenda cada um dos movimentos possíveis e coloque-os no final da fila.
Por uma questão de brevidade, definimos uma função y(usando a expressão lambda L) para executar um dos movimentos e aplicá-la para frente e para trás.

Mnemônico
fonte
4

Gelatina , 20 bytes

ḃ2d2;@+*¥\
0çṪEɗ1#Ḣç

Experimente online!

Dennis
fonte
(nota: isso pega uma lista de singleton de uma lista de 2 elementos, por exemplo [[2,5]])
user202729
4

05AB1E , 25 22 20 bytes

Pega uma lista duplamente aninhada como entrada e gera uma lista irregular com cada etapa em uma profundidade de aninhamento.

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

Experimente online!

Explicação

[                      # 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
Emigna
fonte
4

Retina , 72 bytes

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

Experimente online! Apenas dois casos de teste devido às limitações da aritmética unária. Explicação:

\d+
*

Converta para unário.

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

Enquanto a entrada não contém um par de números idênticos ...

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

... corresponde ao último par de cada linha ...

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

... e transforme a linha em duas linhas, uma com o sufixo do primeiro número incrementado e a segunda dobrada, a outra com o primeiro número dobrado e o segundo incrementado.

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

Mantenha a linha com o par correspondente.

_+
$.&

Converta de volta para decimal. 89 versão aritmética decimal não assinada de 88 bytes (funciona também com 0):

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

Experimente online!

Neil
fonte
4

MATL , 24 bytes

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

O tempo de execução é aleatório, mas é finito com probabilidade 1.

O código é muito ineficiente. As entradas que exigem mais de 4 ou 5 etapas têm uma grande probabilidade de tempo limite no intérprete online.

Experimente online!

Explicação

`         % 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)
Luis Mendo
fonte
3

Stax , 29 26 bytes

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

Execute e depure

É uma amplia primeira pesquisa. Parece razoavelmente rápido.

É necessário um par de números inteiros envolto em uma matriz. A saída é uma lista de valores separados por espaço. A cada dois valores representa um par no caminho para a solução.

recursivo
fonte
2

Haskell , 95 bytes

g s|a:_<-[a|a@((x,y):_)<-s,x==y]=a
g s=g$do a@((x,y):_)<-s;[(x*2,y+1):a,(x+1,y*2):a]
h t=g[[t]]

Experimente online! Saídas na ordem inversa, por exemplo, h(2,5)rendimentos [(12,12),(6,11),(3,10),(2,5)].

Laikoni
fonte
2

Vermelho , 142 bytes

Toma a entrada como um bloco duplamente aninhado do par de números inteiros no formato de Red(2, 5) ->2x5

Retorna o resultado como uma lista de pares vermelhos , por exemplo 2x5 3x10 6x11 12x12. Inclui o par inicial.

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]

Experimente online!

Entrada estrita:

A entrada é dois números, por exemplo 2 5

Vermelho , 214 bytes

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]

Experimente online!

Explicação:

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 
]
Galen Ivanov
fonte