Vier Schritte nach links: Vipern. Vier Schritte nach rechts: eine Klippe. Stirb nicht!

28

Einführung

Nehmen wir für einen Moment an, dass die Vipern und die Klippe nur zwei statt drei Schritte entfernt sind.

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

Sie sind leider ein Gefangener eines sadistischen Folterers. Sie müssen in jeder Kurve einen Schritt nach links oder rechts machen. Wenn Sie dies nicht tun, werden Sie sofort erschossen. Sie können Ihre Schritte im Voraus planen, aber sobald Sie den ersten Schritt getan haben, können Sie Ihren Plan nicht mehr ändern. (Und auch nicht trödeln; sie werden dich erschießen.)

Plötzlich kommt eine gute Idee in den Sinn ...

Ah! Ich kann einfach abwechselnd nach rechts und links gehen! Schritt nach rechts, Schritt nach links, Schritt nach rechts, Schritt nach links und so weiter ...

Ah ah ah, nicht so schnell. Wie gesagt, der Folterer ist sadistisch. Sie können wählen, ob Sie jeden Schritt, jeden zweiten Schritt oder jeden dritten Schritt und so weiter machen. Wenn Sie also naiv die Reihenfolge wählen RLRLRL..., können Sie gezwungen werden, jeden zweiten Schritt zu machen, der mit beginnt LL. Oh oh! Du wurdest von Vipern gebissen! Die Dunkelheit überflutet dich und alles andere verschwindet ...

Eigentlich nein, du bist noch nicht tot. Sie müssen sich noch Ihren Plan ausdenken. Nachdem Sie ein paar Minuten darüber nachgedacht haben, stellen Sie fest, dass Sie zum Scheitern verurteilt sind. Es gibt keine Möglichkeit, eine Reihe von Schritten zu planen, die Ihr Überleben garantieren. Das Beste, was Sie sich einfallen lassen können, ist RLLRLRRLLRR. 1 Elf sichere Schritte und nicht mehr. Wenn der zwölfte Schritt ist R, veranlasst der Folterer Sie, jeden Schritt auszuführen, und die letzten drei Schritte schicken Sie von der Klippe. Wenn der zwölfte Schritt ist L, wird der Folterer Sie veranlassen, jeden dritten Schritt zu machen ( LRLL), was Sie direkt in die Brut der Vipern und ihrer tödlichen Bisse bringt.

Sie wählen Rals zwölften Schritt, in der Hoffnung, Ihren Tod so lange wie möglich zu verzögern. Wenn der Wind in Ihren Ohren brüllt, wundern Sie sich…

Was wäre, wenn ich drei Schritte hätte?


Spoiler Alarm!

Du würdest immer noch sterben. Wie sich herausstellt, gibt es unabhängig von der Anzahl der Schritte einen Punkt, an dem Ihr Folterer eine Reihe von Schritten ausführen kann, um sicherzustellen, dass Sie Ihrem tödlichen Schicksal begegnen. 2 Wenn die Vipern und die Klippe drei Schritte entfernt sind, können Sie insgesamt 1160 sichere Schritte ausführen, und wenn sie vier Schritte entfernt sind, gibt es mindestens 13.000 sichere Schritte! 3

Die Herausforderung

Geben Sie bei einer einzelnen Ganzzahl n < 13000eine Folge nsicherer Schritte aus, vorausgesetzt, die Klippe und die Viper sind vier Schritte entfernt.

Regeln

  • Kann entweder ein vollständiges Programm oder eine Funktion sein.
  • Die Eingabe kann über STDIN oder ein Äquivalent oder als Funktionsargument erfolgen.
  • Output müssen zwei verschiedene Zeichen (die sein kann +/-, R/L, 1/0, etc.).
  • Beliebige Leerzeichen in der Ausgabe spielen keine Rolle.
  • Das Hardcodieren einer Lösung ist nicht zulässig. Das würde diese Herausforderung trivialisieren.
  • Ihr Programm sollte (theoretisch) in angemessener Zeit beendet sein. Wie in, n=13000könnte wie ein Monat dauern, aber es sollte nicht mehr als tausend Jahre dauern. Das heißt, keine rohe Gewalt. (Nun, zumindest versuchen Sie es zu vermeiden.)
  • Lebensbonus: Geben Sie eine Reihe von 2000sicheren Schritten. Wenn Sie dies tun, wird der Folterer von Ihrer Hartnäckigkeit, Ausdauer und Voraussicht so beeindruckt sein, dass er Sie am Leben lässt. Diesmal. (Behandeln Sie diese Sequenz als Binärzahl und geben Sie das Dezimaläquivalent für die Überprüfung an. Dies dient zur Belohnung von Antworten, die schnell abgeschlossen werden, da die Beantwortung sehr lange dauern kann.)
  • Punktzahl: Bytes , sofern Sie sich nicht für den Bonus qualifizieren - multiplizieren Sie mit 0,75 .

Überleben!


1 Es gibt eine gute Erklärung für dieses Problem und eine "Lösung" durch einen der Stars von Numberphile, James Grime, auf seinem YouTube-Kanal hier: https://www.youtube.com/watch?v=pFHsrCNtJu4 .

2 Diese 80 Jahre alte Vermutung, bekannt als Erdos 'Diskrepanzproblem, wurde erst kürzlich von Terence Tao bewiesen. Hier ist ein sehr schöner Artikel im Quanta Magazine dazu: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/ .

3 Quelle: Ein SAT-Angriff auf die Erdos-Diskrepanz-Vermutung von Boris Konev und Alexei Lisitsa. Abgerufen von hier: http://arxiv.org/pdf/1402.2184v2.pdf .

El'endia Starman
quelle
1
Also, wenn ich eine Lösung für mache n=13000, werden die ersten 2000 Anweisungen davon einen Bonus gewinnen? Scheint sinnlos, also hast du wahrscheinlich etwas anderes gemeint?
Anatolyg
@anatolyg: Alle Lösungen sollten theoretisch in der Lage sein, n=13000innerhalb eines Jahres, vielleicht zehn, damit umzugehen. Wirst du einen Monat warten n=2000? Wahrscheinlich nicht. Und wenn ja , dann haben Sie den Bonus trotzdem verdient.
El'endia Starman

Antworten:

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

Die Eingabe wird als Befehlszeilenargument verwendet.

Dabei werden fast alle Möglichkeiten ausprobiert (die einzige Einschränkung besteht darin, dass die ersten 8 Schritte nur innerhalb von -1..1 ablaufen sollten). Dabei wird Schritt für Schritt mithilfe einer magischen Voodoo-Heuristik ausgewählt, welchen Weg Sie zuerst ausprobieren möchten.

Es löst 2000 und sogar 4000 innerhalb von 1 Sekunde auf meinem (ziemlich schnellen) Computer. Benötigt mehr RAM für größere Zahlen; Die größte Eingabe, die ich innerhalb von 8 GB gelöst habe, ist 5023 und es dauerte etwa 30 Sekunden.

Dezimale Darstellung der Lösung für 2000 Schritte, wie für den Bonus erforderlich:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

Anhängen , Ybum es in CJam zu konvertieren , um binäre zurück.

Über die Heuristik: Erstens gibt es ein Muster, das ich verwende: Alle 9 Schritte versuchen, die ersten 9 zu wiederholen, außer bei jedem (9 * x) -ten Schritt wird versucht, den x-ten Schritt zu wiederholen. Dies ist inspiriert von der Lösung, die ich heruntergeladen und in meiner Python-Antwort verwendet (fest codiert) habe.

Ich behalte im Auge, wie oft ich von dem Muster abgewichen bin und wie oft ich eine "Kante" erreicht habe (1 Schritt nach dem Sterben). Die heuristische Funktion ist im Grunde eine gewichtete Kombination dieser beiden Zahlen und der Anzahl der bisher ausgeführten Schritte.

Die Heuristik könnte weiter optimiert werden, um die Geschwindigkeit zu verbessern, und es gibt verschiedene Möglichkeiten, einen Zufallsfaktor hinzuzufügen.
Tatsächlich habe ich gerade über multiplikative Funktionen in Bezug auf dieses Problem gelesen, und es sieht so aus, als ob dies eine signifikante Verbesserung darstellen kann (TODO: Implementiere dies später).

Ungolfed und kommentiert:

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);
            }
        }
    }
}
aditsu
quelle
"später" wartet über ein Jahr
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])

Dies ist für eine Brute-Force-ish-Methode ziemlich schnell und dauert nur einige Sekunden für n = 223, aber viel länger für n> = 224.

Erläuterung: Verfolgen Sie eine Liste von Zeichenfolgen-Listenpaaren (s, u), wobei die Liste u so ist, dass u [i] die aktuelle Position ist, nachdem Sie jedem i-ten Schritt in der Zeichenfolge gefolgt sind. Versuchen Sie, für jede Zeichenfolge in der Liste "L" oder "R" hinzuzufügen, und ändern Sie dann die Werte in der Liste, die sich überschneiden. (Wenn die resultierende Zeichenfolge die Länge 10 hat, addieren oder subtrahieren Sie 1 von den Positionen 1, 2, 5 und 10, je nachdem, in welche Richtung Sie sich bewegt haben). Wenn Sie 3 oder -3 überschreiten, werfen Sie das neue Paar weg, andernfalls behalten Sie es in der Liste. Die längsten Saiten bleiben am Ende erhalten. Wenn Sie eine Zeichenfolge mit der Länge n haben, geben Sie sie zurück.

Frikative Melone
quelle
Warum Python 2/3?
26.
Es funktioniert in beiden Fällen genauso. Soll ich einen von ihnen angeben?
Fricative Melone
Wahrscheinlich solltest du. Ich habe mich nur //gewundert , weil ich nicht wusste, dass das in Python 2
verfügbar ist
-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]

Ich denke, dies ist auch für den Bonus qualifiziert, wenn die Idee darin besteht, "schnell beendete Antworten zu belohnen".

Dies ist jedoch eine hartkodierte Antwort, die nicht im Sinne der Herausforderung ist (obwohl dies nicht ausdrücklich verboten war, als ich sie schrieb).

aditsu
quelle
2
Endlich eine Antwort! d ;-)
wizzwizz4