Quattro passi a sinistra: vipere. Quattro passi a destra: una scogliera. Non morire!


28

introduzione

Supponiamo per un momento che le vipere e la scogliera siano a soli due passi, anziché tre.

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

Sfortunatamente sei prigioniero di un sadico torturatore. È necessario fare un passo sia verso sinistra o verso destra ogni turno. In caso contrario, ti sparano all'istante. Puoi pianificare i tuoi passi in anticipo, ma una volta che fai il primo passo, non puoi cambiare il tuo piano. (E nemmeno dilettarsi; ti spareranno.)

All'improvviso, mi viene in mente un'idea brillante ...

Ah! Posso solo alternare passo a destra e sinistra! Passo a destra, passo a sinistra, passo a destra, passo a sinistra e così via ...

Ah ah ah, non così in fretta. Come ho detto, il torturatore è sadico. Possono scegliere se fare ogni passo, o ogni secondo passo, o ogni terzo passo e così via. Quindi, se scegli ingenuamente la sequenza RLRLRL..., possono costringerti a fare ogni secondo passo, che inizia con LL. Uh Oh! Sei stato morso dalle vipere! L'oscurità piomba su di te e tutto il resto svanisce ...

In realtà no, non sei ancora morto. Devi ancora elaborare il tuo piano. Dopo averci pensato per qualche minuto, ti rendi conto di essere condannato. Non c'è modo di pianificare una serie di passaggi che garantiranno la tua sopravvivenza. Il meglio che puoi inventare è RLLRLRRLLRR. 1 Undici passaggi sicuri e non di più. Se il dodicesimo passo è R, allora il Torturatore ti farà fare ogni passo e poi gli ultimi tre passi ti manderanno giù dalla scogliera. Se il dodicesimo passo è L, allora il Torturatore ti farà fare ogni terzo passo ( LRLL), il che ti mette nella covata di vipere e dei loro morsi letali.

Scegli Ril dodicesimo passo, sperando di ritardare la tua morte il più a lungo possibile. Con il vento che ruggisce nelle orecchie, ti chiedi a te stesso ...

E se avessi tre passaggi?


Avviso spoiler!

Moriresti ancora. A quanto pare, indipendentemente da quanti passi hai, ci sarà qualche punto in cui, indipendentemente dalla scelta che fai, c'è una sequenza di passi che il tuo torturatore può scegliere per assicurarti di incontrare il tuo destino mortale. 2 Tuttavia, quando le vipere e la scogliera sono a tre passi di distanza, puoi fare un totale di 1160 passi sicuri e quando sono a quattro passi, ci sono almeno 13.000 passi sicuri! 3

La sfida

Dato un singolo numero intero n < 13000, genera una sequenza di npassaggi sicuri, supponendo che la scogliera e le vipere siano a quattro passi di distanza.

Regole

  • Può essere un programma completo o una funzione.
  • L'input può essere acquisito tramite STDIN o equivalente o come argomento di funzione.
  • Uscita deve avere due caratteri distinti (che può essere +/-, R/L, 1/0, ecc).
  • Qualsiasi spazio bianco nell'output non ha importanza.
  • Non è consentita la codifica hardware di una soluzione. Ciò banalizzerebbe questa sfida.
  • Il tuo programma dovrebbe (in teoria) terminare in un discreto periodo di tempo. Come in, n=13000potrebbe richiedere un mese, ma non dovrebbe richiedere mille anni o più. Cioè, nessuna forza bruta. (Beh, almeno cerca di evitarlo.)
  • Bonus vita: fornire una serie di 2000passaggi sicuri. Se lo fai, il Torturatore sarà così impressionato dalla tua tenacia, perseveranza e previdente che ti lasceranno vivere. Questa volta. (Tratta questa sequenza come un numero binario e fornisci l'equivalente decimale per la verifica. Questo ha lo scopo di premiare le risposte che finiscono rapidamente poiché le risposte possono richiedere molto tempo.)
  • Punteggio: byte , a meno che non si qualifichi per il bonus - moltiplicare per 0,75 .

Sopravvivere!


1 C'è una buona spiegazione di questo problema e "soluzione" di una delle star di Numberphile, James Grime, sul suo canale YouTube qui: https://www.youtube.com/watch?v=pFHsrCNtJu4 .

2 Questa congettura di 80 anni, nota come il problema della discrepanza di Erdos, è stata recentemente dimostrata da Terence Tao. Ecco un bellissimo articolo su Quanta Magazine a riguardo: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/ .

3 Fonte: A SAT Attack on the Erdos Discrepancy Conjecture , di Boris Konev e Alexei Lisitsa. Estratto da qui: http://arxiv.org/pdf/1402.2184v2.pdf .


1
Quindi, se faccio una soluzione per n=13000, le prime 2000 istruzioni di esso vinceranno un bonus? Sembra inutile, quindi probabilmente intendevi qualcos'altro?
anatolyg

@anatolyg: Tutte le soluzioni dovrebbero teoricamente essere in grado di gestire n=13000entro un anno, forse dieci. Aspetterai un mese n=2000? Probabilmente no. E se lo fai , allora ti meriti comunque il bonus.
El'endia Starman,

Risposte:


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);}}}}

L'input viene considerato come argomento della riga di comando.

Questo prova quasi tutte le possibilità (l'unica limitazione è che i primi 8 passi dovrebbero andare solo entro -1..1), andando passo dopo passo, usando un euristico vudù magico per scegliere quale modo provare per primo.

Risolve 2000 e persino 4000 entro 1 secondo sul mio computer (abbastanza veloce). Ha bisogno di più RAM per numeri più grandi; l'ingresso più grande che ho risolto in 8 GB è 5023 e ci sono voluti circa 30 secondi.

Rappresentazione decimale della soluzione per 2000 passaggi, come richiesto per il bonus:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

Aggiungi Ybad esso in CJam per riconvertire in binario.

Informazioni sull'euristico: in primo luogo, sto usando un modello: ogni 9 passaggi tenta di ripetere i primi 9, tranne ogni (9 * x) passaggio tenta di ripetere il passaggio x. Questo si ispira alla soluzione che ho scaricato e usato (hardcoded) nella mia risposta Python.

Sto tenendo traccia del numero di volte che ho deviato dal modello, e anche il numero di volte che ho raggiunto un "limite" (1 passo dalla morte). La funzione euristica è fondamentalmente una combinazione ponderata di quei 2 numeri e il numero di passi compiuti finora.

L'euristica potrebbe essere ulteriormente ottimizzata per migliorare la velocità e ci sono diversi modi per aggiungere anche un fattore casuale.
In effetti, ho appena letto delle funzioni moltiplicative in relazione a questo problema e sembra che ciò possa fornire un miglioramento significativo (TODO: implementarlo in seguito).

Ungolf e commentato:

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);
            }
        }
    }
}

"dopo" attende oltre un anno
CalculatorFeline

1

Python 2, 236 byte

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

Questo è abbastanza veloce, per un metodo brute-force-ish, richiede solo pochi secondi per n = 223, ma molto più lungo per n> = 224.

Spiegazione: Tenere traccia di un elenco di coppie di elenchi di stringhe (s, u), in cui l'elenco u è tale che u [i] è la posizione corrente dopo aver seguito ogni passaggio della stringa. Per ogni stringa nell'elenco, prova ad aggiungere "L" o "R", quindi modifica i valori nell'elenco che si intersecano. (cioè se la stringa risultante ha lunghezza 10, aggiungi o sottrai 1 dalle posizioni 1,2,5 e 10, secondo le direzioni che hai spostato). Se superi 3 o -3 butta via la nuova coppia, altrimenti tienila nella lista. Le stringhe più lunghe vengono mantenute alla fine. Una volta che hai una stringa di lunghezza n, restituiscila.


Perché python 2/3?
Rɪᴋᴇʀ

Funziona allo stesso modo in uno dei due. Devo specificarne uno?
Fricative Melon,

Probabilmente dovresti. Mi stavo solo chiedendo perché non sapevo che //fosse disponibile in Python 2.
Rɪᴋᴇʀ

-2

Python 2, 729 byte

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]

Penso che questo si qualifichi anche per il bonus se l'idea è "premiare le risposte che finiscono rapidamente".

Tuttavia, questa è una risposta codificata, che non è nello spirito della sfida (anche se non esplicitamente vietata quando l'ho scritta).


2
Finalmente una risposta! d ;-)
wizzwizz4,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.