Apporter une paire d'entiers à l'égalité

51

Cela a été inspiré par un problème de mathématique que j’ai vu quelque part sur Internet mais ne me souviens plus où (MISE À JOUR: le problème original a été trouvé sur les énigmes mathématiques subreddit avec une preuve à condition que cela soit possible, voir aussi ce post de Math SE ), demandant une preuve si le processus suivant est possible pour toute paire d'entiers quelconque (de ce que je me souviens, il était possible pour toute paire donnée):

Étant donné une paire d’entiers, j et k, doublez-en un et ajoutez-en un, créant ainsi une paire de nouveaux entiers, à savoir, (j, k) -> (j + 1, k * 2) ou (j * 2, k + 1). Répétez ensuite ce processus avec ces entiers, l'objectif étant que la paire d'entiers soit égale.

Ces exemples donnés ne sont pas nécessairement optimaux mais montrent comment ce processus peut être effectué sur des nombres entiers, positifs, négatifs ou nuls:

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

Défi

Créez un programme qui donne deux entiers et affiche la liste des étapes nécessaires pour rendre ces entiers égaux en incrémentant plusieurs fois et en doublant l'autre

Caractéristiques

  • La solution ne doit pas nécessairement être optimale, mais elle doit être résolue en un nombre fini d'étapes pour toute paire arbitraire.
  • L'entrée doit être deux entiers

  • La sortie peut être toute sortie raisonnable indiquant clairement les entiers résultants de chaque étape, par exemple:

    • une chaîne avec deux délimiteurs distincts (tout symbole, espace, etc.), un pour chaque entier d'une paire et un pour chaque paire
      • par exemple, entrée j, k: 2, 5 -> sortie: 3,10; 6,11; 12,12
    • une liste de listes d'entiers
      • par exemple, entrée j, k: 2, 5 -> sortie: [[3, 10], [6, 11], [12, 12]]
  • Si l'entrée est une paire de nombres égaux, vous pouvez sortir n'importe quoi pourvu que ce soit cohérent avec d'autres réponses non triviales.

    • par exemple
      • si l'entrée [2, 5] a une sortie [[3, 10], [6, 11], [12, 12]], qui n'inclut pas la paire d'entrée, l'entrée [4, 4] ne doit alors rien émettre.
      • si l'entrée [2, 5] a la sortie [[2, 5], [3, 10], [6, 11], [12, 12]], qui inclut la paire d'entrée, alors l'entrée [4, 4] devrait sortie [[4, 4]].
  • Les méthodes IO standard s'appliquent et les échappatoires standard sont interdites

  • Ceci est le code de golf si la réponse la plus courte en octets gagne

JMigst
la source
13
C'est un beau premier défi, BTW. Bienvenue chez PPCG!
Arnauld
@Arnauld Merci! Merci également d’avoir signalé l’erreur, j’ai fait tous les exemples à la main et je devrais commencer par mettre en œuvre moi-même une solution
JMigst,
La sortie peut-elle être inversée? Eg [(12,12),(6,11),(3,10),(2,5)]pour l'entrée (2,5)?
Laikoni
1
@Laikoni Etant donné que toutes les étapes requises sont encore disponibles, je pense que c'est
correct
1
Je l'ai ajouté à l'OEIS en tant que A304027 . La paire (34,23) semble être particulièrement difficile.
Peter Kagey

Réponses:

10

JavaScript (ES6), 111 90 83 octets

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

Essayez-le en ligne!

Commenté

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
la source
9

Haskell, 70 69 octets

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

Essayez-le en ligne!

Un simple BFS. Garde une trace des étapes dans une liste de paires.

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
la source
7

Python 3 , 90 74 72 octets

-2 octets grâce à 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)

Essayez-le en ligne!

Prend les entrées sous forme de liste 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
la source
4

Pyth, 41 octets

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

Essayez-le ici

Explication

C'est une recherche assez simple, en largeur d'abord. Conservez une file d'attente de séquences possibles ( J) et jusqu'à l'obtention d'une paire correspondante, prenez la séquence suivante, collez chacun des mouvements possibles et mettez-les à la fin de la file d'attente.
Par souci de brièveté, nous définissons une fonction y(en utilisant l'expression lambda L) pour effectuer l'un des mouvements, et l'appliquons à la fois en avant et en arrière.

Mnémonique
la source
4

Gelée , 20 octets

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

Essayez-le en ligne!

Dennis
la source
(note: cela prend une liste de singleton d'une liste de 2 éléments, par exemple [[2,5]])
user202729
4

05AB1E , 25 22 20 octets

Prend une liste doublement imbriquée en entrée et génère une liste en dents de scie avec chaque étape à une profondeur de nid.

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

Essayez-le en ligne!

Explication

[                      # 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
la source
4

Retina , 72 octets

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

Essayez-le en ligne! Seulement deux cas de test en raison des limitations de l'arithmétique unaire. Explication:

\d+
*

Convertir en unaire.

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

Bien que l’entrée ne contienne pas une paire de nombres identiques ...

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

... correspondre à la dernière paire sur chaque ligne ...

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

... et tournez la ligne en deux lignes, l'une suffixée du premier nombre incrémenté et du deuxième doublé, l'autre suffixée du premier nombre doublé et du deuxième incrémenté.

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

Gardez la ligne avec la paire correspondante.

_+
$.&

Reconvertir en décimal. 89 Version arithmétique décimale non signée de 88 octets (fonctionne également avec 0):

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

Essayez-le en ligne!

Neil
la source
4

MATL , 24 octets

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

Le temps d'exécution est aléatoire, mais il est fini avec une probabilité 1.

Le code est très inefficace. Les entrées nécessitant plus de 4 ou 5 étapes ont une grande probabilité d'extinction dans l'interprète en ligne.

Essayez-le en ligne!

Explication

`         % 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
la source
3

Stax , 29 26 octets

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

Exécuter et déboguer

C'est une première recherche en profondeur. Cela semble assez rapide.

Il faut une paire d'entiers doublée d'un tableau. La sortie est une liste de valeurs séparées par des espaces. Toutes les deux valeurs représentent une paire dans le chemin d'accès à la solution.

récursif
la source
2

Haskell , 95 octets

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

Essayez-le en ligne! Les sorties sont inversées, par exemple les h(2,5)rendements [(12,12),(6,11),(3,10),(2,5)].

Laikoni
la source
2

Rouge , 142 octets

Prend l’entrée comme un bloc doublement imbriqué de la paire d’entiers au format Red(2, 5) ->2x5

Renvoie le résultat sous forme de liste des paires rouges , par exemple 2x5 3x10 6x11 12x12. Inclut la paire initiale.

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]

Essayez-le en ligne!

Entrée stricte:

L'entrée est deux nombres, par exemple 2 5

Rouge , 214 octets

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]

Essayez-le en ligne!

Explication:

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
la source