Simpan pilot!

12

Pertanyaan

Kami ditangkap oleh robot tentara di stasiun ruang angkasa mereka. Pilot kapal ruang angkasa kami ada di penjara yang ada di level 1. Hanya ada satu cara bagaimana melarikan diri dan menyelamatkan pilot kapal ruang angkasa Anda. Itu berarti bergerak dari level N ke level 1. Namun karena sangat berisiko Anda harus pergi ke penjara dengan jumlah langkah seminimal mungkin.

Kondisi

  • Ada 4 cara bagaimana memindahkan:

    1. Pindah dari level N ke level N - 1 e.g. from 12 to 11
    2. Pindah dari level N ke level N +1 e.g. from 12 to 13
    3. Gunakan teleportasi dari level 2k ke level k e.g. from 12 to 6
    4. Gunakan teleportasi dari level 3k ke level k e.g. from 12 to 4
  • Teleport hanya satu arah (Anda bisa mendapatkan dari 12 hingga 4 tetapi tidak mungkin untuk mendapatkan dari 4 hingga 12)

  • Setiap tindakan mengambil satu langkah

Memasukkan

Masukan harus dibaca dari STDIN, atau alternatif terdekat dalam bahasa pemrograman Anda. Input terdiri dari bilangan bulat di nmana 1 <= n <= 10^8.

Keluaran

Output harus menjadi jumlah minimum langkah yang diperlukan untuk pergi dari nke level 1.

Contohnya

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

Cobalah kode program yang akan membantu kita menyelamatkan pilot kapal ruang angkasa kita dari penjara dalam waktu singkat dan kembali ke rumah!

Kode terpendek akan menang!

Thomas Fürst
sumber
7
Dianjurkan (tetapi tidak wajib) untuk menunggu setidaknya satu minggu sebelum menerima jawaban. Bahkan jika Anda berniat untuk mengubah jawaban yang diterima jika jawaban yang lebih pendek akan diposting di masa depan, orang lain mungkin mendapat kesan bahwa kontes ini "berakhir" dan jangan berpartisipasi.
Dennis
1
Tantangan ini mengingatkan saya pada permainan yang saya mainkan dengan kalkulator saya: Saya akan mengetik angka yang mengisi layar dan mencoba membagi dengan 2, 3, atau 5 sebanyak yang saya bisa, kemudian menambahkan / mengurangi 1 dan melanjutkan.
Arcturus

Jawaban:

8

Pyth, 32 byte

L?<b3tbhSsmm+h%_Wkbdy/+kbd2tS3yQ

Cobalah online: Demonstrasi atau Test Suite

Penjelasan:

Saya mengubah masalah sedikit. Saya mendefinisikan 4 operasi baru, yang menggantikan 4 operasi pertanyaan.

  • level / 2(dihitung sebagai (level % 2) + 1langkah - langkah, karena Anda mungkin perlu memindahkan level ke bawah terlebih dahulu untuk berteleportasi)
  • (level + 1) / 2(dihitung sebagai (level % 2) + 1langkah)
  • level / 3(dihitung sebagai (level % 3) + 1langkah)
  • (level + 1) / 3(dihitung sebagai (-level % 3) + 1langkah)

Dengan desain operasi ini dapat diterapkan untuk setiap nomor, jika nomor tersebut adalah 0 mod 2, 1 mod 2, 0 mod 3, 1 mod 3atau 2 mod 3.

Anda dapat dengan mudah memikirkan, mengapa ini berhasil. Gagasan utamanya adalah, bahwa setidaknya ada satu solusi optimal, yang tidak memiliki dua gerakan (bergerak ke bawah) atau dua gerakan (bergerak ke atas) secara berurutan. Bukti: Jika Anda memiliki solusi, yang memiliki dua gerakan seperti itu secara berurutan, daripada Anda dapat menggantinya dan membuat solusi lebih kecil atau sama panjang. Misalnya Anda bisa mengganti (pindah ke atas, pindah ke atas, teleportasi dari 2k ke k) dengan (teleportasi dari 2k ke k, pindah ke atas) dan serupa dalam semua kasus lainnya.

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

Fungsi ymenggunakan memoisasi secara implisit dan oleh karena itu runtime tidak meledak.

Jakube
sumber
1
Gagasan utamanya adalah, bahwa tidak pernah ada dua gerakan (bergerak ke bawah) atau dua (bergerak ke atas) secara berturut-turut dalam solusi optimal. - bagaimana dengan 29 -> 28 -> 27 -> 9 -> 3 -> 1? Jika itu adalah solusi optimal, bagaimana Anda memutuskan bahwa selalu ada alternatif untuk jalur dua-atas / dua-turun, yang tidak mengarah ke wilayah angka yang lebih canggung?
TessellatingHeckler
1
@ TessellatingHeckler Mungkin saya harus lebih tepat. Ada setidaknya satu solusi optimal, yang tidak memiliki dua (bergerak turun) atau dua (naik) gerakan berturut-turut. Misalnya 29 -> 30 -> 10 -> 9 -> 3 -> 1
Jakube
Saya tidak mengatakan itu salah, hanya saja saya tidak bisa "dengan mudah memikirkan mengapa ini berhasil". Saya beralasan: rute tercepat ke kamar 1 dimulai dengan kekuatan tiga, dibagi dengan tiga setiap gerakan. Jadi rute tercepat untuk angka di dekat kekuatan tiga adalah pengurangan berulang atau penambahan untuk mendapatkan kekuatan tiga, kemudian bagi berulang kali dengan 3. Jika sebaliknya mereka mulai dengan bergerak bergerak n / 2, mereka semakin jauh dari kekuatan tiga, dan karena itu melewati rute tercepat yang mungkin. Saya tidak melihat bagaimana mereka akan / selalu / menemukan rute lain yang sama pendeknya; sepertinya mereka berada di wilayah dengan pilihan 'buruk' sekarang.
TessellatingHeckler
4

Python, 176 byte

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]

Brute force sepanjang jalan; daftar semua angka 1 to 100,000,000pada komputer 64bit adalah ~ 800Mb memori.

Indeks daftar mewakili angka, nilai mewakili jarak dari 1 dalam langkah penyelamatan yang diizinkan.

  • Atur daftar [1] = 0 yang berarti "dapat dicapai dalam 0 langkah".
  • untuk setiap nomor dalam daftar yang dapat dijangkau dalam 0 langkah (yaitu 1)
    • set angka + 1, angka-1, angka * 2, angka * 3 dapat dicapai dalam 1 langkah
  • untuk setiap nomor dalam daftar yang dapat dijangkau dalam 1 langkah (yaitu 0,2,2,3)
    • atur angka + 1, angka-1, angka * 2, angka * 3 dapat dicapai dalam 2 langkah
  • ... dll. hingga setiap indeks daftar tercapai.

Runtime lebih dari 10 menit. * ahem *.

Komentar kode

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.

Lain

  • Jika Anda menjalankannya dengan PythonWin, Anda dapat mengakses daftar L pada juru bahasa sesudahnya.
  • Setiap kamar memiliki jalur ke kapten dalam 30 gerakan atau kurang.
  • Hanya satu kamar yang berjarak 30 langkah - kamar 72.559.411 - dan ada 244 kamar yang berjarak 29 langkah.
  • Ini mungkin memiliki karakteristik runtime yang mengerikan untuk kasus maksimum, tetapi salah satu komentar pertanyaannya adalah " @Geobits semua program yang seharusnya menemukan cara terpendek untuk 20.000 kasus uji dalam 5 menit " dan menguji 1-20.001 dalam waktu <6 detik.
TessellatingHeckler
sumber
2

Python 2 ... 1050

ditulis dengan buruk, tidak disunat, tidak optimal.

Membaca level awal pada stdin, mencetak jumlah langkah minimum pada 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())
pelaku diet
sumber
2

Kode mesin x86 32-bit, 59 byte

Dalam hex:

31c9487435405031d231dbb103f7f14a7c070f94c301d008d353e8e3ffffff5b00c3585331d2b102f7f152e8d2ffffff5a00d05a38d076019240c3

Bahasa mesin sendiri tidak memiliki konsep input standar. Karena tantangannya adalah komputasi murni, saya memilih untuk menulis fungsi dengan mengambil parameter input EAXdan mengembalikan hasilnya AL.

Matematika di balik kode dijelaskan dengan baik oleh @Jakube: pencarian dilakukan hanya di antara jalur yang memiliki teleport diselingi dengan tidak lebih dari satu gerakan satu tingkat. Kinerja adalah sekitar 12000 kasus uji per detik di ujung bawah kisaran input dan 50 kasus per detik di ujung atas. Konsumsi memori adalah 12 byte ruang stack per tingkat rekursi.

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
sumber