Caminos de Collatz: adelante y atrás a lo largo de la conjetura de Collatz

8

La conjetura de Collatz es una conjetura muy conocida. Toma un entero positivo; si es par, divida por 2, de lo contrario, multiplique por 3 y agregue 1. Repita hasta que llegue 1o algo más suceda. La conjetura es que este proceso siempre llega 1.

También puedes revertir el proceso. Comience en 1, multiplique por 2 y bifurque a multiply by 3 and add 1números, cuando llegue a un número par 1 (mod 3), es decir , reste 1 y divida por 3.

Un camino de Collatz combina los dos, tratando de pasar de un número a otro con esas cuatro operaciones.

Por ejemplo, para llegar 20desde 1:

1     *2
2     *2
4     *2
8     *2
16    *2
5     (-1)/3
10    *2
20    *2

También puede llegar 3desde 10restando 1 y dividiendo entre 3.

Con estas herramientas, puede recorrer una ruta de Collatz de un número a otro. Por ejemplo, la ruta de 20a 3es (dividir por 2), (restar 1, dividir por 3).

En resumen, las operaciones disponibles son:

n * 2       always
n // 2      if n % 2 == 0
n * 3 + 1   if n % 2 == 1
(n-1) // 3  if n % 6 == 4

Nota: no todos los caminos de Collatz son cortos. a(7,3)podría funcionar

7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 2, 4, 8, 16, 5, 10, 3

pero un camino más corto es

7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 3

El reto

Encuentre la longitud del camino Collatz más corto entre dos enteros positivos, py q.

  • La entrada es cualquiera de los dos enteros positivos menos que 2^20para evitar el desbordamiento de enteros. El método de entrada queda a discreción del golfista. Los enteros pueden ser los mismos, en cuyo caso, la longitud de la ruta de Collatz es 0.
  • La salida debe ser un número entero, indicando la longitud del camino Collatz más corto entre py q.

Casos de prueba

a(2,1)
1

a(4,1)
1         # 4 -> 1

a(3,1)
6         # 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 1

a(11,12)
11        # 11 -> 34 -> 17 -> 52 -> 26 -> 13
          # -> 40 -> 20 -> 10 -> 3 -> 6 -> 12

a(15,9)
20        # 46 -> 23 -> 70 -> 35 -> 106 -> 53 -> 160 -> 80 -> 40 -> 13
          # -> 26 -> 52 -> 17 -> 34 -> 11 -> 22 ->  7 -> 14 -> 28 -> 9

Muchas gracias a orlp por su ayuda para aclarar este desafío.

Como siempre, si el problema no está claro, hágamelo saber. ¡Buena suerte y buen golf!

Sherlock9
fuente
1
Nuestras computadoras no soportarían un conjunto de al menos 2 ^ 31 elementos.
@MatthewRoh Challenge ha sido editado desde entonces.
Sherlock9
Esto es más o menos un desafío para encontrar el camino de la teoría de gráficos . Y estoy bastante seguro de que teníamos uno casi idéntico antes.
flawr
Posible duplicado de caminos más cortos en un gráfico divisor
error
2
@flawr No estoy de acuerdo con el duplicado. Sí, ambos desafíos quieren encontrar una ruta en un gráfico, pero los gráficos son diferentes, y codificar la estructura del gráfico en su respuesta es la parte única, IMO. Vea, por ejemplo, mi respuesta y compárela con las respuestas en su pregunta 'duplicada'.
orlp

Respuestas:

3

Haskell, 17015815714614313713511510910810610100 99 bytes

a!b=length$fst$break(elem b)$iterate(>>= \n->2*n:cycle[div n 2,n*3+1]!!n:[div(n-1)3|mod n 6==4])[a]

¡No esperaba que mi versión original fuera mucho más fácil de jugar, este también es el trabajo de @nimi @Lynn y @Laikoni!

¡Gracias @Laikoni por un byte, @Lynn por 11 14 20 21 bytes, @nimi por 8 bytes!

Esto expande el árbol de números visitados (comenzando por a) paso a paso, y verifica en cada paso si llegamos al número dado b.

falla
fuente
Te perdiste un espacio:iterate s [a] -> iterate s[a]
Laikoni
Sweet ~ Inlining sahorra tres bytes más. iterate(nub.concat.map f)[a]Además, ¿realmente necesitas el nub?
Lynn
Dime cuando hayas terminado de jugar golf: D Muchas gracias. Lamentablemente, todavía tengo problemas para entender las mónadas.
flawr
@nimi Nuevamente, muchas gracias, ¡nunca esperé que fuera tanto más golfable! No lo sabía breaky span, ¡realmente útil!
defecto
1
Reemplazar [div n 2,n*3+1]!!mod n 2con cycle[div n 2,n*3+1]!!nguardar un byte más :)
Lynn
2

Python 2, 110 bytes

a=lambda p,q,s={0}:1+a(p,q,s.union(*({p,n*2,[n/2,n*3+1][n%2]}|set([~-n/3]*(n%6==4))for n in s)))if{q}-s else-1
orlp
fuente
1

Pyth, 30 bytes

|q*FQ2ls-M.pm.u&n2N?%N2h*3N/N2

Pruébalo en línea

Cómo funciona

Tome la longitud de la diferencia simétrica de las dos secuencias de Collatz hacia adelante que comienzan en los dos números de entrada y terminan en 2. La única excepción es si la entrada es [1, 2]o [2, 1], lo cual es un caso especial.

  *FQ                        product of the input
|q   2                       if that equals 2, return 1 (True), else:
            m                  map for d in input:
             .u                  cumulative fixed-point: starting at N=d, iterate N ↦
               &n2N?%N2h*3N/N2     N != 2 and (N*3 + 1 if N % 2 else N/2)
                                 until a duplicate is found, and return the sequence
          .p                   permutations
        -M                     map difference
       s                       concatenate
      l                        length
Anders Kaseorg
fuente
1

Python 2, 156 179 191 209 181 172 177 171 bytes

Desde un camino Collatz puede ser imaginado como a(1,p)y a(1,q)unidos en el primer número que es común a ambas secuencias y a(1,n)es la conjetura original de Collatz, esta función calcula la secuencia de Collatz de py q, y calcula la longitud de allí. Este no es un golf bonito, por lo que las sugerencias de golf son muy bienvenidas. La única excepción es cuándo p or q == 1. Entonces, ya que podemos saltar directamente de 4que 1en lugar de una secuencia regular de Collatz, tenemos que restar un paso del resultado.

Editar: Mucha corrección de errores.

Editar: Montones y montones de corrección de errores

f=lambda p:[p]if p<3else f([p//2,p*3+1][p%2])+[p]
def a(p,q):
 i=1;c=f(p);d=f(q)
 if sorted((p,q))==(1,2):return 1
 while c[:i]==d[:i]!=d[:i-1]:i+=1
 return len(c+d)-2*i+2

Pruébalo en línea!

Sherlock9
fuente
Su enfoque no funciona, por ejemplo, a(3,1)devuelve 7 mientras que debería devolver 6, ya que el camino más corto es3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 1
error
@flawr Editado. Esperemos que funcione ahora
Sherlock9
¿Por qué supone que el algoritmo que describió funciona? ¿No podría un camino más corto consistir en varias veces "ir y venir"?
error
2
Deje que fdenote un paso adelante, bun paso atrás en la secuencia de collatz. El patrón b->fno puede estar en una ruta más corta, ya que es la identidad ( fse deshace ben cualquier caso). Por lo tanto, la ruta más corta solo puede consistir en patrones f->f, f->by b->b. Eso significa de nuevo que el camino más corto es siempre de la forma f->f->...->fo b->b->...->bof->...->f->b->...->b
flawr
3
PD: Tengo la impresión de que su número de bytes va en la dirección incorrecta. : D
flawr
0

JavaScript (ES6), 135 bytes

f=(x,y,a=[(s=[],s[0]=s[x]=1,x)],z=a.shift())=>z-y?[z*2,z/2,z%2?z*3+1:~-z/3].map(e=>e%1||s[e]?0:s[a.push(e),e]=-~s[z])&&f(x,y,a):~-s[y]

Realiza una búsqueda de amplitud. xes el número de partida, yel destino, aun conjunto de valores de prueba, suna serie del número de pasos incluido en la cadena de x, zel valor actual. Si zy yno son iguales, calcular z*2, z/2y ya sea z*3+1o (z-1)/3, dependiendo de si zes par o impar, entonces filtrar las fracciones y los valores vistos anteriormente y añadirlos a la lista de búsqueda.

Neil
fuente
0

Python 2, 80 bytes

p=lambda n:n-2and{n}|p([n/2,n*3+1][n%2])or{n}
lambda m,n:m*n==2or len(p(m)^p(n))

Tome la longitud de la diferencia simétrica de las dos secuencias de Collatz hacia adelante que comienzan en los dos números de entrada y terminan en 2. La única excepción es si la entrada es 1, 2 o 2, 1, lo cual es un caso especial.

Anders Kaseorg
fuente