Sauvez le pilote!

12

Question

Nous sommes capturés par une armée de robots sur leur station spatiale. Notre pilote de vaisseau spatial est dans la prison qui est au niveau 1. Il n'y a qu'une seule façon de s'échapper et c'est de sauver votre pilote de vaisseau spatial. Cela signifie passer du niveau N au niveau 1. Cependant, parce que c'est très risqué, vous devez vous rendre à la prison dans le moins d'étapes possible.

Conditions

  • Il y a 4 façons de se déplacer:

    1. Passer du niveau N au niveau N - 1 e.g. from 12 to 11
    2. Passer du niveau N au niveau N + 1 e.g. from 12 to 13
    3. Utilisez la téléportation du niveau 2k au niveau k e.g. from 12 to 6
    4. Utilisez la téléportation du niveau 3k au niveau k e.g. from 12 to 4
  • Les téléports sont à sens unique (vous pouvez obtenir de 12 à 4 mais il est impossible d'obtenir de 4 à 12)

  • Chaque action prend une étape

Contribution

L'entrée doit être lue depuis STDIN, ou l'alternative la plus proche dans votre langage de programmation. L'entrée se compose d'un entier n1 <= n <= 10^8.

Production

La sortie doit être le nombre minimum d'étapes nécessaires pour passer du nniveau 1.

Exemples

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

Essayez de coder un programme qui nous aidera à sauver notre pilote de vaisseau spatial de la prison dans les plus brefs délais et à rentrer chez nous!

Le code le plus court gagnera!

Thomas Fürst
la source
7
Il est conseillé (mais pas obligatoire) d'attendre au moins une semaine avant d'accepter une réponse. Même si vous avez l'intention de modifier la réponse acceptée si une réponse plus courte est publiée à l'avenir, d'autres peuvent avoir l'impression que ce concours est "terminé" et s'abstenir de participer.
Dennis
1
Ce défi me rappelle un jeu auquel je jouais avec ma calculatrice: je tapais un nombre qui remplit l'écran et essayais de diviser par 2, 3 ou 5 autant que je le pouvais, puis en ajoutant / soustrayant 1 et en continuant.
Arcturus du

Réponses:

8

Pyth, 32 octets

L?<b3tbhSsmm+h%_Wkbdy/+kbd2tS3yQ

Essayez-le en ligne: démonstration ou suite de tests

Explication:

J'ai transformé un peu le problème. Je définis 4 nouvelles opérations, qui remplacent les 4 opérations de la question.

  • level / 2(compte comme des (level % 2) + 1étapes, car vous devrez peut-être d'abord descendre d'un niveau pour vous téléporter)
  • (level + 1) / 2(compte comme des (level % 2) + 1étapes)
  • level / 3(compte comme des (level % 3) + 1étapes)
  • (level + 1) / 3(compte comme des (-level % 3) + 1étapes)

De par sa conception ces opérations peuvent être appliquées à chaque numéro, si le nombre est 0 mod 2, 1 mod 2, 0 mod 3, 1 mod 3ou 2 mod 3.

Vous pouvez facilement penser à pourquoi cela fonctionne. L'idée principale est qu'il existe au moins une solution optimale qui n'a pas deux mouvements (déplacer vers le bas) ou deux (déplacer vers le haut) d'affilée. Preuve: Si vous avez une solution, qui a deux de ces mouvements consécutifs, vous pouvez les remplacer et rendre la solution plus petite ou égale en longueur. Par exemple, vous pouvez remplacer (monter, monter, téléporter de 2k à k) par (téléporter de 2k à k, monter) et similaire dans tous les autres cas.

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

La fonction yutilise implicitement la mémorisation et donc le runtime n'explose pas.

Jakube
la source
1
L'idée principale est qu'il n'y a jamais deux mouvements (déplacer vers le bas) ou deux (déplacer vers le haut) d'affilée dans la solution optimale. - qu'en est-il de 29 -> 28 -> 27 -> 9 -> 3 -> 1? Si c'est une solution optimale, comment avez-vous décidé qu'il y a toujours une alternative au chemin à deux vers le haut / deux vers le bas, qui ne mène pas à une région de nombres plus délicate?
TessellatingHeckler
1
@TessellatingHeckler J'aurais peut-être dû être plus précis. Il existe au moins une solution optimale, qui n'a pas deux mouvements (déplacer vers le bas) ou deux (déplacer vers le haut) d'affilée. Par exemple: 29 -> 30 -> 10 -> 9 -> 3 -> 1
Jakube
Je ne dis pas que c'est faux, seulement que je ne peux pas "facilement penser à pourquoi ça marche". Je raisonnais: la route la plus rapide vers la salle 1 commence à une puissance de trois, divisée par trois à chaque mouvement. Donc, le chemin le plus rapide pour les nombres proches d'une puissance de trois est la soustraction ou l'addition répétée pour obtenir la puissance de trois, puis diviser à plusieurs reprises par 3. Si au lieu de cela, ils commencent par se déplacer en se déplaçant n / 2, ils s'éloignent de la puissance de trois, et donc passé l'itinéraire le plus rapide possible. Je ne vois pas comment ils trouveront / trouveront toujours une autre route aussi courte; il semble qu'ils se trouvent actuellement dans une région où les choix sont «pires».
TessellatingHeckler
4

Python, 176 octets

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]

Force brute tout le long; une liste de tous les nombres 1 to 100,000,000sur un ordinateur 64 bits représente environ 800 Mo de mémoire.

L'index de la liste représente les nombres, les valeurs représentent la distance de 1 dans les étapes de sauvetage autorisées.

  • Définir la liste [1] = 0 signifiant "accessible en 0 étapes".
  • pour chaque numéro de la liste accessible en 0 étapes (ie 1)
    • définir le numéro + 1, le numéro-1, le numéro * 2, le numéro * 3 accessible en 1 étape
  • pour chaque numéro de la liste accessible en 1 étape (ie 0,2,2,3)
    • définir le numéro + 1, le numéro-1, le numéro * 2, le numéro * 3 accessible en 2 étapes
  • ... etc. jusqu'à ce que chaque index de liste soit atteint.

Le temps d'exécution est un peu plus de 10 minutes. * ahem *.

Commentaires sur le code

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.

Autre

  • Si vous l'exécutez dans PythonWin, vous pouvez ensuite accéder à la liste L dans l'interpréteur.
  • Chaque pièce a un chemin vers le capitaine en 30 coups ou moins.
  • Une seule pièce est à 30 déménagements - la pièce 72 559 411 - et il y a 244 pièces à 29 déménagements.
  • Il peut avoir de terribles caractéristiques d'exécution pour le cas maximum, mais l'une des questions commentées est " @Geobits tous les programmes qui devraient trouver les moyens les plus courts pour 20000 cas de test en 5 minutes " et il teste 1-20,001 en <6 secondes.
TessellatingHeckler
la source
2

Python 2 ... 1050

mal écrit, non golfé, non optimal.

Lit le niveau de démarrage sur stdin, imprime le nombre minimum d'étapes sur 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())
diète
la source
2

Code machine x86 32 bits, 59 octets

En hex:

31c9487435405031d231dbb103f7f14a7c070f94c301d008d353e8e3ffffff5b00c3585331d2b102f7f152e8d2ffffff5a00d05a38d076019240c3

Le langage machine n'a pas en soi de concept d'entrée standard. Étant donné que le défi est purement informatique, j'ai choisi d'écrire une fonction prenant le paramètre d'entrée EAXet retournant le résultat AL.

Le calcul du code est bien expliqué par @Jakube: la recherche n'est effectuée que parmi les chemins ayant des téléports entrecoupés de pas plus d'un mouvement à un niveau. Les performances sont d'environ 12 000 cas de test par seconde dans l'extrémité inférieure de la plage d'entrée et 50 cas par seconde dans l'extrémité supérieure. La consommation de mémoire est de 12 octets d'espace de pile par niveau de récursivité.

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
la source