pengantar
Dalam tantangan ini, kita akan berhadapan dengan grafik tak terarah tak terbatas tertentu, yang saya sebut grafik pembagi tinggi . Node-nya adalah bilangan bulat mulai dari 2. Ada tepi antara dua node a <b jika a membagi b dan a 2 ≥ b . Subgraf yang dibentuk oleh rentang 2 hingga 18 terlihat seperti ini:
16-8 12 18
\|/ |/|
4 6 9 10 15 14
| |/ |/ |
2 3 5 7 11 13 17
Dapat ditunjukkan bahwa grafik pembagi tinggi tak terbatas terhubung, sehingga kita dapat bertanya tentang jalur terpendek antara dua node.
Masukan dan keluaran
Input Anda adalah dua bilangan bulat a dan b . Anda dapat mengasumsikan bahwa 2 ≤ a ≤ b <1000 . Output Anda adalah panjang jalur terpendek antara a dan b dalam grafik pembagi tinggi tak terbatas. Ini berarti jumlah tepi di jalan.
Anda mungkin menemukan fakta berikut ini berguna: selalu ada jalur optimal dari a ke b yang pertama kali meningkat lalu menurun, dan hanya mengunjungi node yang benar-benar kurang dari 2b 2 . Khususnya, karena b <1000 Anda hanya perlu mempertimbangkan node yang kurang dari 2 000 000.
Contohnya
Pertimbangkan input 3
dan 32
. Satu jalur yang mungkin antara node 3 dan 32 adalah
3 -- 6 -- 12 -- 96 -- 32
Jalur ini memiliki empat tepi, dan ternyata tidak ada jalur yang lebih pendek, jadi output yang benar adalah 4
.
Sebagai contoh lain, jalur optimal untuk 2
dan 25
adalah
2 -- 4 -- 8 -- 40 -- 200 -- 25
jadi output yang benar adalah 5
. Dalam hal ini, tidak ada jalur optimal yang berisi node 50 = lcm(2, 25)
.
Aturan dan penilaian
Anda dapat menulis program atau fungsi lengkap. Hitungan byte terendah menang, dan celah standar tidak diizinkan. Tidak ada batasan waktu atau memori, jadi pemaksaan kasar diperbolehkan.
Uji kasus
2 2 -> 0
2 3 -> 4
2 4 -> 1
2 5 -> 5
3 5 -> 4
6 8 -> 2
8 16 -> 1
12 16 -> 2
16 16 -> 0
2 25 -> 5
3 32 -> 4
2 256 -> 3
60 77 -> 3
56 155 -> 3
339 540 -> 2
6 966 -> 4
7 966 -> 2
11 966 -> 4
2 997 -> 7
991 997 -> 4
FindShortestPath
melanggar batasan tentang celah standar? Jika ya, beri tahu saya dan saya akan menghapus kiriman saya.Jawaban:
Matlab,
218190175 byteTerima kasih @beaker untuk pintasan di dalam langkah pemanjangan daftar!
Ini adalah implementasi dijkstra yang relatif mudah:
tidak ada belitan hari ini
sumber
l=zeros(1,a*b);
Anda dapat menggunakanl(a*b)=0;
, yang melakukan hal yang samaJavaScript (ES6), 186 byte
Menggunakan fungsi penolong
g
untuk menghitung semua jalur naik darim
dann
pada gilirannya ke batas yang disediakan, lalu menjumlahkan jalur bersama dan mengembalikan nilai terendah.sumber
Mathematica 98 byte
Saya mengasumsikan bahwa fungsi bawaan,
FindShortestPath
tidak melanggar batasan tentang celah standar. Jika ya, beri tahu saya dan saya akan menghapus kiriman ini.Brute force, karenanya lambat dengan nilai besar
b
. Saya masih memikirkan cara untuk mempercepatnya.Ini mengatur grafik dengan tepi yang sesuai antara node dari
a
keb^2
.FindShortestPath
menemukan jalur terpendek dalam grafik.Length
menghitung node;Length -1
adalah jumlah tepi.Thread[# <-> Range[2, #] #] &
menghasilkan tepi grafik penuh. Sebagai contoh,Thread[# <-> Range[2, #] #]&[5]
akan menghasilkan tepi{5 <-> 2*5, 5 <-> 3*5, 5 <-> 4*5, 5 <-> 5*5}
, yaitu{5 <-> 10, 5 <-> 15, 5 <-> 20, 5 <-> 25}
,.sumber
Matlab
(195) (185) (181) (179)(173)Contoh panggilan fungsi:
Semua test case puas
Penjelasan:
Sebelum memulai dengan penjelasan, mari kita buktikan beberapa lemmas "bukan yang hijau":
Lemma (1): Jalur optimal antara dua angka
(a,b)
ada dengan cara node pertama meningkat kemudian menurun.Mengapa Ini hanya dibuktikan karena jumlah bilangan bulat maksimal yang membagi angka berapa
a
pun masing-masing sebesar angkaa
itu sendiri, sehingga sebagai pendekatan yang cerdas kita harus memilih untuk mengalikana
sebanyak mungkin untuk membuatnya cukup besar, kemudian membaginya dengan nilai yang lebih besar. Jika kita melakukan jalan memutar, jumlahnyaa
menyusut, jadi kita perlu lebih banyak iterasi untuk memperbanyaknya secara bertahap sehingga kita tidak perlu.Lemma (2): Dari angka
a
keb
, jikagcd(a,b)=1
a
dikalikan denganb
, jikab
lebih besar daria
itu akan dikalikan dengan angka yang diketahuic
, jikagcd>1
a
harus dikalikan secara bertahap dengan pembagib/gcd
nama terbesard
yang memverifikasi kondisia >= d
juga ketika semuad
adalah minimum lebih besar daria
,a
terimaa*c
lagi.Asumsi ini sederhana untuk membuktikan setiap simpul awal
a
harus dikalikan hingga mencapai kelipatan terkecila
danb
karenanya kita kalikan dengan proporsib*gcd
awal dengan maksimum yang memverifikasi kondisi utama, yang menjamin selalu jalur terpendek untuk smp sebelum proses pembagian dimulai, atau ketikad
tidak tersedia angkac
dikalikan dengana
untuk membuat kondisi yang valida>=d
untuk tahap pertama ini.Lemma (3): Dari kelipatan grafik-ultimum
a
keb
, gcd dari angka ini danb
itub
sendiriNah ini hanya konsekuensi dari manipulasi sebelumnya, dan langkah terakhir yang tersisa juga dilakukan secara bertahap dengan pembagi terbesar yang tidak melebihi akar kuadratnya.
Dilema: Berapakah angka optimal
c
untuk dikalikan secara iteratif dengan angkaa
yang mengarah langsung ke kondisi pembukaan untuk tahap 1 kemudian ultimum?Pertanyaan bagus, untuk situasi sederhana apa pun ada pesta sederhana, jadi anggaplah contoh dua sisi
(a,b)=(4,26)
difaktorkan seperti ini:Terlepas dari
gcd=2
bilangan bulat terkecil yang harus dikalikan dengan2
untuk mencapai13
adalah7
, tetapi jelas dikesampingkan, karena lebih besar dari 2, jadi a kuadrat.Appearenlty pada contoh kedua
(a,b)=(10,26)
di atasc
diukur sebagai integer terendah dari1
ke5
yang melebihi13/5
karena itu memenuhi kondisi grafik-scaling, yang3
, maka langkah selanjutnya di sini adalah mengalikan dengan3
Mengapa ini karena, begitu kita harus mengalikan dengan
2*13/gcd=13
untuk mencocokkan dengan sisi kedua tabel, jumlah sampah yang kita tambahkan sebelumnya secara optimal terkecil, dan bergerak sepanjang grafik diminimalkan, jika kita dikalikan dengan nilai yang lebih besar seperti10
peluang untuk membagi dengan paling sedikit waktu berkurang, dan itu akan meningkat 1 langkah membagi lain untuk mencapai tujuan kami2*13
. yang disebutkan untuk:13*2*5*10/2*5
lalu13*2*5/5
. Sementara, jelas di sini jumlah yang akan dibagi adalah5*3<13*2
dan satu hal lagi ........ MATI MATI ...
Ini adalah hasil komparatif saya dengan @ flawr 's hanya memperhatikan bahwa saya membuat batas atas untuk eksekusi berdasarkan algoritma flawr, butuh terlalu banyak waktu!
Anda dapat memasukkan rentang pemindaian mulai dan berakhir sebagai variabel a dan b di header kode yang dapat dikompilasi online.
sumber