Rette den Piloten!

12

Frage

Wir werden von einer Roboterarmee auf ihrer Raumstation gefangen genommen. Unser Raumschiffpilot befindet sich im Gefängnis auf Stufe 1. Es gibt nur einen Weg zu entkommen und er rettet Ihren Raumschiffpilot. Das bedeutet, dass Sie von Level N auf Level 1 wechseln müssen. Da dies jedoch sehr riskant ist, müssen Sie das Gefängnis in möglichst wenigen Schritten erreichen.

Bedingungen

  • Es gibt 4 Möglichkeiten, sich zu bewegen:

    1. Wechseln Sie von Ebene N zu Ebene N - 1 e.g. from 12 to 11
    2. Wechseln Sie von Level N zu Level N + 1 e.g. from 12 to 13
    3. Benutze den Teleport von Level 2k nach Level k e.g. from 12 to 6
    4. Benutze den Teleport von Level 3k nach Level k e.g. from 12 to 4
  • Teleports sind nur in eine Richtung möglich (Sie können zwischen 12 und 4 wählen, es ist jedoch unmöglich, zwischen 4 und 12 zu wählen).

  • Jede Aktion macht einen Schritt

Eingang

Die Eingabe sollte von STDIN oder der nächstgelegenen Alternative in Ihrer Programmiersprache gelesen werden. Die Eingabe besteht aus einer Ganzzahl, nwobei 1 <= n <= 10^8.

Ausgabe

Die Ausgabe sollte die Mindestanzahl von Schritten sein, die erforderlich sind, um von nStufe 1 zu gelangen.

Beispiele

Level         Minimum number of steps
1             0
8             3
10            3
267           7
100,000,000   25

Versuchen Sie, ein Programm zu programmieren, mit dem wir unseren Raumschiff-Piloten in kürzester Zeit aus dem Gefängnis retten und nach Hause zurückkehren können!

Der kürzeste Code gewinnt!

Thomas Fürst
quelle
7
Es ist ratsam (aber nicht obligatorisch), mindestens eine Woche zu warten, bevor Sie eine Antwort annehmen. Auch wenn Sie beabsichtigen, die akzeptierte Antwort zu ändern, falls in Zukunft eine kürzere Antwort veröffentlicht wird, können andere den Eindruck erwecken, dass dieser Wettbewerb "vorbei" ist und von der Teilnahme Abstand nehmen.
Dennis
1
Diese Herausforderung erinnert mich an ein Spiel, das ich mit meinem Taschenrechner gespielt habe: Ich habe eine Zahl eingegeben, die den Bildschirm ausfüllt, und versucht, so viel wie möglich durch 2, 3 oder 5 zu teilen, dann 1 zu addieren / zu subtrahieren und fortzufahren.
Arcturus

Antworten:

8

Pyth, 32 Bytes

L?<b3tbhSsmm+h%_Wkbdy/+kbd2tS3yQ

Probieren Sie es online aus: Demo oder Test Suite

Erläuterung:

Ich habe das Problem ein wenig verändert. Ich definiere 4 neue Operationen, die die 4 Operationen der Frage ersetzen.

  • level / 2(Zählt als (level % 2) + 1Schritte, da Sie möglicherweise zuerst eine Stufe nach unten verschieben müssen, um zu teleportieren.)
  • (level + 1) / 2(zählt als (level % 2) + 1Schritte)
  • level / 3(zählt als (level % 3) + 1Schritte)
  • (level + 1) / 3(zählt als (-level % 3) + 1Schritte)

Mit dem Design können diese Vorgänge an jede Nummer angewandt werden, wenn die Zahl 0 mod 2, 1 mod 2, 0 mod 3, 1 mod 3oder 2 mod 3.

Sie können sich leicht überlegen, warum dies funktioniert. Die Hauptidee ist, dass es mindestens eine optimale Lösung gibt, die nicht zwei (nach unten) oder zwei (nach oben) Bewegungen hintereinander hat. Beweis: Wenn Sie eine Lösung haben, die zwei solcher Bewegungen hintereinander hat, können Sie diese ersetzen und die Lösung kleiner oder gleich lang machen. Zum Beispiel könnten Sie ersetzen (nach oben bewegen, nach oben bewegen, von 2k nach k teleportieren) durch (von 2k nach k teleportieren, nach oben bewegen) und Ähnliches in allen anderen Fällen.

L?<b3tbhSsmm+h%_Wkbdy/+kbd2tS3yQ
L                                 define a function y(b), which returns:
 ?<b3                               if b < 3:
     tb                               return b-1
                                    else:
          m                tS3        map each d in [2, 3] to:
           m              2             map each k in [0, 1] to:
              %_Wkbd                      (b mod d) if k == 0 else (-b mod d)
             h                            +1, this gives the additional steps
            +       y/+kbd                + f((b+k)/d) (recursive call)
         s                            combine the two lists
       hS                             and return the minimum element
                               yQ call y with input number

Die Funktion yverwendet implizit Memoization und daher explodiert die Laufzeit nicht.

Jakube
quelle
1
Die Hauptidee ist, dass es in der optimalen Lösung niemals zwei (Abwärts-) oder zwei (Aufwärts-) Bewegungen hintereinander gibt. - Was ist mit 29 -> 28 -> 27 -> 9 -> 3 -> 1? Wenn dies eine optimale Lösung ist, wie haben Sie dann entschieden, dass es immer eine Alternative zum Zwei-Auf- / Zwei-Ab-Pfad gibt, die nicht in einen unangenehmeren Bereich von Zahlen mündet?
TessellatingHeckler
1
@TessellatingHeckler Vielleicht hätte ich genauer sein sollen. Es gibt mindestens eine optimale Lösung, die nicht zwei (nach unten) oder zwei (nach oben) Bewegungen hintereinander hat. ZB 29 -> 30 -> 10 -> 9 -> 3 -> 1
Jakube
Ich sage nicht, dass es falsch ist, nur, dass ich nicht "leicht darüber nachdenken kann, warum es funktioniert". Ich überlegte: Der schnellste Weg zu Raum 1 beginnt mit einer Dreierpotenz, die bei jeder Bewegung durch drei geteilt wird. Der schnellste Weg für Zahlen in der Nähe der Dreierpotenz ist also die wiederholte Subtraktion oder Addition, um die Dreierpotenz zu erhalten, und die Division durch 3. Wenn sie stattdessen anfangen, indem sie sich um n / 2 bewegen, entfernen sie sich weiter von der Dreierpotenz. und damit über den schnellstmöglichen Weg. Ich sehe nicht ein, wie sie / immer / einen anderen Weg finden werden, der ebenso kurz ist; es scheint, als ob sie sich in einer Region befinden, in der es derzeit „schlimmer“ geht.
TessellatingHeckler
4

Python, 176 Bytes

n=int(1e8);s,f,L=0,input(),[1,0]+[n]*(n-1)
def h(q):
 if 0<=q<=n and L[q]>s:L[q]=s+1
while n in L:
 for i,v in enumerate(L):
  if v==s:map(h,(i-1,i+1,i*2,i*3))
 s+=1
print L[f]

Rohe Gewalt den ganzen Weg; eine Liste aller Nummern1 to 100,000,000 auf einem 64-Bit-Computer enthält ca. 800 MB Speicher.

Der Listenindex repräsentiert die Zahlen, Werte repräsentieren den Abstand von 1 in erlaubten Rettungsschritten.

  • Set list [1] = 0 bedeutet "in 0 Schritten erreichbar".
  • für jede Nummer in der Liste, die in 0 Schritten erreichbar ist (dh 1)
    • Set Nummer + 1, Nummer-1, Nummer * 2, Nummer * 3 in 1 Schritt erreichbar
  • für jede Nummer in der Liste, die in 1 Schritt erreichbar ist (dh 0,2,2,3)
    • Set Nummer + 1, Nummer-1, Nummer * 2, Nummer * 3 in 2 Schritten erreichbar
  • ... usw. bis jeder Listenindex erreicht ist.

Die Laufzeit beträgt etwas mehr als 10 Minuten. *Hm*.

Code-Kommentare

n=int(1e8)           # max input limit.
s=0                  # tracks moves from 1 to a given number.
f=input()            # user input.

L=[1,0]+[n]*(n-1)    # A list where 0 can get to room 1 in 1 step,
                     # 1 can get to itself in 0 steps,
                     # all other rooms can get to room 1 in 
                     # max-input-limit steps as a huge upper bound.


def helper(q):
    if 0<=q<=n:      # Don't exceed the list boundaries.
      if L[q]>s:     # If we've already got to this room in fewer steps
                     # don't update it with a longer path.
          L[q]=s+1   # Can get between rooms 1 and q in steps+1 actions.


while n in L:        # until there are no values still at the 
                     # original huge upper bound

 for i,v in enumerate(L):
  if v==s:                            # only pick out list items
                                      # rechable in current s steps,
      map(helper,(i-1,i+1,i*2,i*3))   # and set the next ones reachable
                                      # in s+1 steps.

 s+=1                                 # Go through the list again to find
                                      # rooms reachable in s+1 steps

print L[f]                            # show answer to the user.

Andere

  • Wenn Sie es in PythonWin ausführen, können Sie anschließend im Interpreter auf die Liste L zugreifen.
  • In maximal 30 Zügen hat jeder Raum einen Weg zum Kapitän.
  • Nur ein Raum ist 30 Züge entfernt - Raum 72.559.411 - und es gibt 244 Räume, die 29 Züge entfernt sind.
  • Es kann schreckliche Laufzeitmerkmale für den Maximalfall haben, aber einer der Fragenkommentare ist " @Geobits alle Programme, die in 5 Minuten die kürzesten Wege für 20000 Testfälle finden sollten " und es testet 1-20.001 in <6 Sekunden.
TessellatingHeckler
quelle
2

Python 2 ... 1050

schlecht geschrieben, ungolfed, nicht optimal.

Liest den Startlevel auf stdin, druckt die minimale Anzahl von Schritten auf stdout.

def neighbors(l):
    yield l+1
    yield l-1
    if not l%3:yield l/3
    if not l%2:yield l/2

def findpath(start, goal):
    closedset = set([])
    openset = set([start])
    came_from = {}
    g_score = {}
    g_score[start] = 0
    f_score = {}
    f_score[start] = 1
    while len(openset) > 0:
        current = min(f_score, key=f_score.get)
        if current == goal:
            return came_from
        else:
            openset.discard(current)
        del f_score[current]
        closedset.add(current)
        for neighbor in neighbors(current):
            if neighbor in closedset:
                continue
            tentative_g_score = g_score[current] + 1
            if (neighbor not in openset) or (tentative_g_score < g_score[neighbor]):
                came_from[neighbor] = current
                g_score[neighbor] = tentative_g_score
                f_score[neighbor] = tentative_g_score + 1
                openset.add(neighbor)
def min_path(n):
    path = findpath(n,1)
    i,current = 0,1
    while current <> n:
        i+=1
        current = path[current]
    return i
print min_path(input())
Dieter
quelle
2

32-Bit-x86-Computercode, 59 Byte

In hex:

31c9487435405031d231dbb103f7f14a7c070f94c301d008d353e8e3ffffff5b00c3585331d2b102f7f152e8d2ffffff5a00d05a38d076019240c3

Die Maschinensprache an sich kennt keine Standardeingabe. Da die Herausforderung rein rechnerisch ist, habe ich mich dafür entschieden, eine Funktion zu schreiben, die Eingabeparameter in EAXund Ergebnis in zurückgibt AL.

Die Mathematik hinter dem Code wird von @Jakube gut erklärt: Die Suche wird nur auf den Pfaden durchgeführt, auf denen sich Teleports mit nicht mehr als einer einstufigen Bewegung befinden. Die Leistung beträgt ca. 12000 Testfälle pro Sekunde am unteren Ende des Eingabebereichs und 50 Fälle pro Sekunde am oberen Ende. Der Speicherverbrauch beträgt 12 Byte Stapelspeicherplatz pro Rekursionsstufe.

0:  31 c9               xor ecx, ecx  
_proc:
2:  48                  dec eax       
3:  74 35               je _ret       ;if (EAX==1) return 0;
5:  40                  inc eax       ;Restore EAX
6:  50                  push eax      
7:  31 d2               xor edx, edx  ;Prepare EDX for 'div'
9:  31 db               xor ebx, ebx  
b:  b1 03               mov cl, 3     
d:  f7 f1               div ecx       ;EAX=int(EAX/3); EDX=EAX%3
f:  4a                  dec edx       ;EDX is [-1..1]
10: 7c 07               jl _div3      ;EDX<0 (i.e. EAX%3==0)
12: 0f 94 c3            sete bl       ;BL=EDX==0?1:0
15: 01 d0               add eax, edx  ;If EAX%3==2, we'd go +1 level before teleport
17: 08 d3               or bl, dl     ;BL=EAX%3!=0
_div3:
19: 53                  push ebx      ;Save register before...
1a: e8 e3 ff ff ff      call _proc    ;...recursive call
1f: 5b                  pop ebx       
20: 00 c3               add bl, al    ;BL is now # of steps if taken 3n->n route (adjusted) less one
22: 58                  pop eax       ;Restore original input parameter's value
23: 53                  push ebx      
24: 31 d2               xor edx, edx  
26: b1 02               mov cl, 2     
28: f7 f1               div ecx       ;EAX=EAX>>1; EDX=EAX%2
2a: 52                  push edx      ;Save register before...
2b: e8 d2 ff ff ff      call _proc    ;...another recursive call
30: 5a                  pop edx       
31: 00 d0               add al, dl    ;AL is now # of steps if using 2n->n route (adjusted) less one
33: 5a                  pop edx       
34: 38 d0               cmp al, dl    ;Compare two routes
36: 76 01               jbe _nsw      
38: 92                  xchg eax, edx ;EAX=min(EAX,EDX)
_nsw:
39: 40                  inc eax       ;Add one for the teleport itself
_ret:
3a: c3                  ret           
meden
quelle