Cuatro pasos a la izquierda: víboras. Cuatro pasos a la derecha: un acantilado. ¡No te mueras!


28

Introducción

Supongamos por un momento que las víboras y el acantilado están a solo dos pasos de distancia, en lugar de tres.

            o
           ---
Hsss!       |
 ';;' ___  /_\  ___  _
                      |

Eres, desafortunadamente, un cautivo de un torturador sádico. Usted debe dar un paso hacia la izquierda o hacia la derecha cada vez. Si no lo haces, te matan a tiros al instante. Se le permite planificar sus pasos de antemano, pero una vez que da el primer paso, no puede cambiar su plan. (Y no te entretengas tampoco; te dispararán).

De repente, se me ocurre una idea brillante ...

Ah! ¡Puedo alternar paso a derecha e izquierda! Paso a la derecha, paso a la izquierda, paso a la derecha, paso a la izquierda, etc.

Ah ah ah, no tan rápido. Como dije, el torturador es sádico. Pueden elegir si das cada paso, o cada segundo paso, o cada tercer paso, y así sucesivamente. Entonces, si elige ingenuamente la secuencia, RLRLRL...entonces pueden forzarlo a dar cada segundo paso, que comienza con LL. ¡UH oh! ¡Has sido mordido por víboras! La oscuridad se apodera de ti y todo lo demás se desvanece ...

En realidad no, todavía no estás muerto. Aún tiene que elaborar su plan. Después de pensarlo durante unos minutos, te das cuenta de que estás condenado. No hay forma de planificar una serie de pasos que garanticen su supervivencia. Lo mejor que se te ocurre es RLLRLRRLLRR. 1 Once pasos seguros y nada más. Si el duodécimo paso es R, entonces el torturador te hará dar cada paso y luego los últimos tres pasos te enviarán por el precipicio. Si el duodécimo paso es L, entonces el torturador te hará dar cada tercer paso ( LRLL), lo que te coloca en la prole de las víboras y sus picaduras letales.

Eliges Rel duodécimo paso, esperando retrasar tu desaparición el mayor tiempo posible. Con el viento rugiendo en tus oídos, te preguntas a ti mismo ...

¿Y si tuviera tres pasos?


¡Alerta de spoiler!

Aún morirías. Como resultado, no importa cuántos pasos tengas, habrá un punto en el que, sin importar qué opción elijas, hay una secuencia de pasos que tu Torturador puede elegir para asegurarte de cumplir con tu destino mortal. 2 Sin embargo, cuando las víboras y el acantilado están a tres pasos, puedes tomar un total de 1160 pasos seguros y cuando están a cuatro pasos, ¡hay al menos 13,000 pasos seguros! 3

El reto

Dado un solo número entero n < 13000, genera una secuencia de npasos seguros, suponiendo que el acantilado y las víboras estén a cuatro pasos de distancia.

Reglas

  • Puede ser un programa completo o una función.
  • La entrada puede tomarse a través de STDIN o equivalente, o como un argumento de función.
  • Salida debe tener dos caracteres distintos (que puede ser +/-, R/L, 1/0, etc.).
  • Cualquier espacio en blanco en la salida no importa.
  • Codificar una solución no está permitido. Eso trivializaría este desafío.
  • Su programa debería (en teoría) terminar en una cantidad de tiempo decente. Como en, n=13000podría tomar como un mes, pero no debería tomar mil años o más. Es decir, sin fuerza bruta. (Bueno, al menos trata de evitarlo).
  • Bono de vida: proporciona una serie de 2000pasos seguros. Si haces esto, el torturador quedará tan impresionado con tu tenacidad, perseverancia y previsión que te dejarán vivir. Esta única vez. (Trate esta secuencia como un número binario y proporcione el equivalente decimal para la verificación. Esto tiene como objetivo recompensar las respuestas que terminan rápidamente, ya que las respuestas pueden tardar mucho tiempo).
  • Puntuación: bytes , a menos que califiques para el bono: multiplícalo por 0,75 .

¡Sobrevivir!


1 Hay una buena explicación de este problema y "solución" de una de las estrellas de Numberphile, James Grime, en su canal de YouTube aquí: https://www.youtube.com/watch?v=pFHsrCNtJu4 .

2 Esta conjetura de 80 años, conocida como el problema de discrepancia de Erdos, fue probada recientemente por Terence Tao. Aquí hay un muy buen artículo en Quanta Magazine sobre esto: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/ .

3 Fuente: A SAT Attack on the Erdos Discrepancy Conjecture , por Boris Konev y Alexei Lisitsa. Recuperado de aquí: http://arxiv.org/pdf/1402.2184v2.pdf .


1
Entonces, si hago una solución n=13000, ¿las primeras instrucciones de 2000 ganarán un bono? Parece inútil, ¿entonces probablemente quisiste decir algo más?
anatolyg

@anatolyg: Teóricamente, todas las soluciones deberían poder manejarse n=13000dentro de un año, tal vez diez. ¿Vas a esperar un mes n=2000? Probablemente no. Y si lo haces , entonces mereces la bonificación de todos modos.
El'endia Starman

Respuestas:


6

Java, 915 * 0.75 = 686.25

import java.util.*;class E implements Comparable<E>{static
int n,m,t,u;byte[]a;int k=2,b,d;E(){a=new byte[5];a[1]=13;}E(E
x){a=Arrays.copyOf(x.a,n+1);k=x.k;d=x.d;b=x.b;}int
g(int x){return(a[x]+1)%3-1;}void s(int x,int y){a[x]=(byte)(a[x]/3*3+(y+3)%3);}void
S(int x,int y){a[x]=(byte)(a[x]%3+(y+3)*3);}E
w(int x){if(g(k)==-x)return null;E e=new E(this);e.s(k,x);e.S(e.k++,x);for(m=0;++m<k;)if(k%m<1){u=e.a[m]/3-3+x;if(u==(k<9?2:4)*x)return
null;e.S(m,u);if(u==3*x){e.b++;if(k+m<=n){if(e.g(k+m)==x)return
null;e.s(k+m,-x);}}}return e;}public int compareTo(E o){m=d-o.d+(b-o.b)/60+(o.k-k)/150;return
m==0?o.k-k:m;}public static void main(String[]a){n=Integer.valueOf(a[0]);Queue<E>q=new PriorityQueue<>();q.add(new
E());for(;;){E x=q.remove(),y;if(x.k>n){for(t=0;++t<x.k;)System.out.print((x.g(t)+1)/2);return;}t=x.g(x.k<9?1:x.k%9==0?x.k/9:x.k%9);y=x.w(t);if(y!=null)q.add(y);y=x.w(-t);if(y!=null){y.d++;q.add(y);}}}}

La entrada se toma como un argumento de línea de comandos.

Esto intenta casi todas las posibilidades (la única restricción es que los primeros 8 pasos solo deben ir dentro de -1..1), yendo paso a paso, usando una heurística de vudú mágico para elegir qué forma probar primero.

Resuelve 2000 e incluso 4000 en 1 segundo en mi computadora (bastante rápida). Necesita más RAM para números más grandes; La entrada más grande que resolví dentro de 8 GB es 5023 y tardó unos 30 segundos.

Representación decimal de la solución para 2000 pasos, según lo solicitado para la bonificación:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

Anexar Yba ella en Cjam para convertir de nuevo a binario.

Acerca de la heurística: primero, hay un patrón que estoy usando: cada 9 pasos intenta repetir los primeros 9, excepto que cada paso (9 * x) intenta repetir el paso x. Esto está inspirado en la solución que descargué y usé (codificado) en mi respuesta de Python.

Llevo un registro de la cantidad de veces que me desvié del patrón, y también la cantidad de veces que llegué a un "borde" (1 paso de morir). La función heurística es básicamente una combinación ponderada de esos 2 números y el número de pasos dados hasta ahora.

La heurística podría ajustarse aún más para mejorar la velocidad, y también hay varias formas de agregarle un factor aleatorio.
De hecho, acabo de leer acerca de las funciones multiplicativas en relación con este problema, y ​​parece que eso puede proporcionar una mejora significativa (TODO: implemente esto más adelante).

Ungolfed y comentó:

import java.util.*;

public class Erdos implements Comparable<Erdos> {
    static int n; // input (requested number of steps)
    static int m, t, u; // auxiliary variables

    byte[] a; // keeps each step and sum combined into 1 byte
    int k = 2; // number of steps + 1 (steps are 1-based)
    int edge; // number of times we got to an edge
    int diff; // number of differences from the expected pattern

    // start with one step
    Erdos() {
        a = new byte[5];
        set(1, 1);
        setSum(1, 1);
    }

    // copy constructor
    Erdos(Erdos x) {
        a = Arrays.copyOf(x.a, n + 1);
        k = x.k;
        diff = x.diff;
        edge = x.edge;
    }

    // get the x'th step (can be -1, 0 or 1)
    int get(int x) {
        return (a[x] + 1) % 3 - 1;
    }

    // set the x'th step
    void set(int x, int y) {
        a[x] = (byte) (a[x] / 3 * 3 + (y + 3) % 3);
    }

    // get the sum of every x'th step (should be within -3..3)
    int getSum(int x) {
        return a[x] / 3 - 3;
    }

    // set the sum of every x'th step
    void setSum(int x, int y) {
        a[x] = (byte) (a[x] % 3 + (y + 3) * 3);
    }

    // try to add a step with value x (1 or -1)
    Erdos grow(int x) {
        if (get(k) == -x) // predetermined step doesn't match
            return null;
        Erdos e = new Erdos(this);
        e.set(k, x);
        e.setSum(e.k++, x);
        for (m = 0; ++m < k;)
            if (k % m < 1) { // check all divisors of k
                u = e.getSum(m) + x; // updated sum
                if (u == (k < 9 ? 2 : 4) * x) // use limit 2 for the first 8 steps, 4 for the rest
                    return null; // dead
                e.setSum(m, u);
                if (u == 3 * x) { // we're at an edge
                    e.edge++;
                    if (k + m <= n) { // predetermine future step - should be going back
                        if (e.get(k + m) == x) // conflict
                            return null;
                        e.set(k + m, -x);
                    }
                }
            }
        return e;
    }

    public int compareTo(Erdos o) { // heuristic function
        m = diff - o.diff + (edge - o.edge) / 60 + (o.k - k) / 150;
        return m == 0 ? o.k - k : m;
    }

    public static void main(String[] a) {
        n = Integer.valueOf(a[0]);
        Queue<Erdos> q = new PriorityQueue<>();
        q.add(new Erdos());
        for (;;) {
            Erdos x = q.remove(), y;
            if (x.k > n) { // we made it
                for (t = 0; ++t < x.k;)
                    System.out.print((x.get(t) + 1) / 2);
                return;
            }
            t = x.get(x.k < 9 ? 1 : x.k % 9 == 0 ? x.k / 9 : x.k % 9); // next step based on the pattern
            y = x.grow(t);
            if (y != null)
                q.add(y);
            y = x.grow(-t);
            if (y != null) {
                y.diff++;
                q.add(y);
            }
        }
    }
}

"más tarde" espera más de un año
CalculatorFeline

1

Python 2, 236 bytes

n=input();r=len;u=[("",[0]*(n//4))]
while n>r(u[-1][0]):
 y,t=u.pop()
 for c in 0,1:
  s=t[:];u+=(y+"LR"[c],s),
  for i in range(r(s)):
   if-~r(y)//-~i*-~i==-~r(y):s[i]+=2*c-1;
   if abs(s[i])>3:u.pop();break;
print(u[-1][0])

Esto es bastante rápido, para un método de fuerza bruta, solo toma unos segundos para n = 223, pero mucho más para n> = 224.

Explicación: realice un seguimiento de una lista de pares de lista de cadenas (s, u), donde la lista u es tal que u [i] es la posición actual después de seguir cada i-ésimo paso en la cadena. Para cada cadena de la lista, intente agregar "L" o "R", luego cambie los valores en la lista que se cruzan. (es decir, si la cadena resultante tiene una longitud 10, sume o reste 1 de las posiciones 1,2,5 y 10, de acuerdo con las instrucciones que movió). Si superas 3 o -3 tira el nuevo par, de lo contrario, mantenlo en la lista. Las cadenas más largas se mantienen al final. Una vez que tenga una cadena de longitud n, devuélvala.


¿Por qué python 2/3?
Rɪᴋᴇʀ

Funciona igual en cualquiera de los dos. ¿Debo especificar uno de ellos?
Melón fricativo

Probablemente deberías. Me preguntaba porque no sabía que //estaba disponible en Python 2.
Rɪᴋᴇʀ

-2

Python 2, 729 bytes

n=0
for x in"eJytVU2LwyAQPWzTvZjjspcsxFYTBdNuQSEF+///1jp+p5o0hYVSBl9nfOObNz1MlAgqzMcEEwQkDyIkFpDYCW0UnChbyZJiK2sfhDcYmu9hT0GdIPQvLduAmoCvvqEssvq84CVCpLzrNcOOspLhY6/KswB6FmoSxGPBcWts7lsMp/0q83da1hgC6k7GoqBir1ruAFIVvWIdTi++oGIAyZw8mkuG03uDDc+rEsSWTmFBwbLgtTF8hl1e/lpCigR7+pM5V9lIqVJBjStzKNRRQDp6UOrvwga6VFrGcWz6YHwLNYWUYeZfWO/DQTq7i4dAxixeszmtFEw7Cr5v9R3lRVF55TDzY6QRrSfzF9NLE7lAZ+vLnGgYLZ/FlCuoRcOugeFduHTqRWmyh1J91XpIndIbEk8jifL8hs8qQ8vjAVoGqhK5Tm/O5svpXd82QH4Azq05kYnhj93PzLbcTisFzXWfDqIC5zsq3jU7UUhSh1R3L4+i4HCXKlrGyywSBttPr2zpL4gCDPtk2HPN5tgZFomzSDPfGAlASus+e4KlLcjS0vPQ0f5/mR/r1s4PcxsgMLRSMp617AveCuup2OCAPBT6yltWrPO9azsbp6fphR87Lc7VzcbEt5F4Ydg/NzhXTA==".decode("base64").decode("zip"):n=n*64+ord(x)
print bin(n)[2:input()+2]

Creo que esto también califica para el bono si la idea es "recompensar las respuestas que terminan rápidamente".

Sin embargo, esta es una respuesta codificada, que no está en el espíritu del desafío (aunque no se rechazó explícitamente cuando la escribí).


2
Finalmente, una respuesta! d ;-)
wizzwizz4
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.