Anda diberi mesin dengan dua register 16-bit, x
dan y
. Register diinisialisasi x=1
dan y=0
. Satu-satunya operasi yang dapat dilakukan mesin adalah penambahan modulo 65536. Yaitu:
x+=y
-x
diganti dengan(x + y) mod 65536
;y
tidak berubahy+=x
- sama untuky
x+=x
-x
diganti dengan2x mod 65536
; sah hanya jikax
adily+=y
- sama untuky
Tujuannya adalah untuk mendapatkan nomor yang telah ditentukan di salah satu register (salah satu x
atau y
).
Tulis sebuah program atau subrutin yang menerima angka (dalam stdin
,, argv
parameter fungsi, atas tumpukan atau tempat konvensional lainnya), dan output sebuah program untuk mendapatkan nomor ini. Outputnya harus menuju stdout
, atau (jika bahasa Anda tidak memiliki stdout
) ke perangkat output konvensional lainnya.
Program keluaran bisa hingga 100% plus 2 langkah jauh dari optimal. Artinya, jika program terpendek untuk mendapatkan nomor target memiliki n
langkah-langkah, solusi Anda tidak lebih dari 2n+2
. Pembatasan ini untuk menghindari solusi "terlalu mudah" (mis. Menghitung 1, 2, 3, ...) tetapi tidak memerlukan optimisasi penuh; Saya berharap bahwa program terpendek adalah yang termudah untuk ditemukan, tetapi tidak dapat memastikan ...
Misalnya: Input = 25. Output:
y+=x
x+=y
x+=y
x+=x
x+=x
x+=x
y+=x
Contoh lain: Untuk setiap angka fibonacci, output memiliki pola bolak-balik ini. Untuk Input = 21, output adalah
y+=x
x+=y
y+=x
x+=y
y+=x
x+=y
y+=x
Kode terpendek (diukur dalam byte) menang.
(Teka-teki ini terinspirasi oleh beberapa kode untuk prosesor 16-bit yang saya harus hasilkan baru-baru ini)
PS Saya bertanya-tanya - untuk nomor berapa program optimal paling lama?
sumber
x+=x
hanya sah jikax
adil? Juga untuk program terpendek saya pikir sesuatu seperti BFS bisa berfungsi.x+=x
hanya bekerja untuk genapx
s, bagaimana bisa contoh untuk input 25 ganda 3?Jawaban:
CJam, 31
Seperti jawaban @Tobia , algoritme saya juga
dicuritanpa malu-malu, terinspirasi oleh jawaban @CChak . Tapi, menggunakan ilmu hitam yaitu CJam, saya berhasil membuat implementasi algoritma yang lebih kecil.Coba di sini.
Golf:
Tidak Disatukan:
Tolong perbaiki saya jika saya salah, tetapi saya percaya bahwa operasi modulo 65536 yang digunakan dalam jawaban dengan algoritma yang sama tidak perlu. Saya menafsirkan pertanyaan sehingga kita dapat mengasumsikan bahwa input akan menjadi integer 16-bit unsigned yang valid, dan nilai menengah atau hasil dari algoritma ini juga akan.
sumber
Perl
10797Posting pertama, jadi begini.
Yang cocok dengan semua kriteria tambahan register, tapi saya tidak menjalankan pemeriksaan lengkap untuk melihat apakah jawaban saya selalu dalam 2n + 2 dari jumlah langkah optimal. Namun, ini masih dalam batas untuk setiap angka Fibonacci.
Berikut ini rincian lebih rinci
Seperti yang saya sebutkan, ini adalah upaya pertama saya bermain golf, jadi saya yakin ini bisa diperbaiki. Juga, saya tidak yakin apakah panggilan subroutine awal harus dihitung dalam panggilan rekursif atau tidak, yang dapat mendorong kita beberapa karakter.
Menariknya kita dapat mengurangi kode dengan 11 byte * dan meningkatkan "efisiensi" kami dalam hal jumlah operasi register, dengan melonggarkan persyaratan bahwa hanya nilai genap yang dapat "digandakan". Saya memasukkannya untuk bersenang-senang di sini:
Mulai addendum:
Sangat menyukai masalah ini, dan saya telah mengotak-atiknya selama beberapa minggu terakhir. Kupikir aku akan memposting hasil saya.
Beberapa angka:
Menggunakan algoritma BFS untuk menemukan solusi optimal, dalam 2 ^ 16 angka pertama hanya ada 18 angka yang membutuhkan 23 langkah. Mereka adalah: 58558, 59894, 60110, 61182, 61278, 62295, 62430, 62910, 63422, 63462, 63979, 64230, 64314, 4486, 64510, 64698, 64854, 65295.
Menggunakan algoritma rekursif yang dijelaskan di atas, angka "paling sulit" untuk dicapai adalah 65535, pada 45 operasi. (65534 mengambil 44, dan ada 14 angka yang mengambil 43 langkah) 65535 juga merupakan keberangkatan terbesar dari optimal, 45 vs 22. Perbedaan 23 langkah adalah 2n +1. (Hanya tiga angka yang mengenai 2n: 65534, 32767, 32751.) Kecuali kasus sepele (nol-langkah), pada rentang yang ditentukan, metode rekursif rata-rata sekitar 1,4 kali solusi optimal.
Intinya: Untuk angka 1-2 ^ 16, algoritma rekursif tidak pernah melewati ambang batas yang ditentukan 2n + 2, jadi jawabannya valid. Saya menduga bahwa itu akan mulai terlalu jauh dari solusi optimal untuk register yang lebih besar / lebih banyak bit.
Kode yang saya gunakan untuk membuat BFS adalah ceroboh, memori intensif, tidak berkomentar, dan tidak sengaja sengaja dimasukkan. Jadi ... Anda tidak harus mempercayai hasil saya, tapi saya cukup percaya diri dalam hasilnya.
sumber
Python 3, 202 byte
(Terima kasih kepada @rasionalis selama beberapa byte)
Inilah solusi yang sangat mendasar. Saya berharap bisa bermain golf dengan baris terakhir dengan lebih baik, tetapi saat ini saya kehabisan ide. Panggil dengan
S(25)
.Program ini hanya melakukan BFS sederhana tanpa caching, jadi sangat lambat. Berikut ini
S(97)
, untuk beberapa keluaran sampel:sumber
Dyalog APL, 49 karakter / byte *
Algoritma tanpa malu-malu terinspirasi oleh jawaban @CChak .
Contoh:
Tidak Disatukan:
* Dyalog APL mendukung legacy charset yang memiliki simbol APL yang dipetakan ke nilai 128 byte atas. Oleh karena itu program APL yang hanya menggunakan karakter ASCII dan simbol APL dapat dianggap sebagai byte == karakter.
sumber
Python, 183
Saya tidak dapat menjamin ini tetap dalam 2x program optimal untuk angka genap, tetapi efisien. Untuk semua input yang valid
0 <= n < 65536
, itu pada dasarnya instan, dan menghasilkan program paling banyak 33 instruksi. Untuk ukuran register sewenang-wenangn
(setelah menetapkan konstanta itu), akan membutuhkanO(n)
waktu paling banyak dengan2n+1
instruksi.Logika Biner
Angka ganjil
n
dapat dihubungi dalam 31 langkah: lakukany+=x
, dapatkanx,y = 1,1
, dan terus gandakanx
denganx+=x
(untuk penggandaan pertamax+=y
, karenax
ganjil untuk memulai).x
akan mencapai setiap kekuatan 2 dengan cara ini (itu hanya shift kiri), dan jadi Anda dapat mengatur bity
menjadi 1 dengan menambahkan kekuatan yang sesuai dari 2. Karena kita menggunakan register 16-bit, dan setiap bit kecuali untuk yang pertama membutuhkan satu penggandaan untuk mencapai dan satuy+=x
untuk ditetapkan, kita mendapatkan maksimal 31 ops.Setiap bilangan genap
n
hanya sejumlah 2, sebut sajaa
, dikalikan dengan angka ganjil, sebut sajam
; yaitun = 2^a * m
, atau setaran = m << a
,. Gunakan proses di atas untuk mendapatkanm
, lalu atur ulangx
dengan menggeser ke kiri sampai menjadi 0. Lakukanx+=y
untuk mengaturx = m
, dan kemudian lanjutkan untuk menggandakanx
, pertama kali menggunakanx+=y
dan kemudian menggunakanx+=x
.Apa pun
a
itu, dibutuhkan16-a
pergeseranx
untuk mendapatkany=m
dana
pergeseran tambahan untuk mengatur ulangx=0
.a
Pergeseran lainx
akan terjadi setelahx=m
. Jadi total16+a
shift digunakan. Ada16-a
bit hingga yang perlu diatur untuk mendapatkanm
, dan masing-masing akan mengambil satuy+=x
. Akhirnya kita membutuhkan langkah tambahan kapanx=0
harus mengaturnya ke mx+=y
,. Jadi dibutuhkan paling banyak 33 langkah untuk mendapatkan angka genap.Anda dapat, tentu saja, menggeneralisasi ini ke register ukuran apa pun, dalam hal ini selalu dibutuhkan paling banyak
2n-1
dan2n+1
ops untukn
bilangan bulat ganjil dan genap , masing-masing.Optimalitas
Algoritma ini menghasilkan program yang mendekati optimal (yaitu di dalam
2n+2
jikan
adalah jumlah minimum langkah) untuk angka ganjil. Untuk bilangan ganjil tertentun
, jikam
bit ke-1 adalah yang terdepan, maka setiap program mengambil setidaknyam
langkah untuk sampai ke ,x=n
atauy=n
karena operasi yang meningkatkan nilai register paling cepat adalahx+=x
atauy+=y
(yaitu penggandaan) dan dibutuhkanm
penggandaan untuk mencapai yangm
bit th dari 1. Sejak algoritma ini memakan waktu paling2m
langkah (paling banyak dua per dua kali lipat, satu untuk pergeseran dan satuy+=x
), setiap ganjil diwakili dekat-optimal.Bahkan angkanya tidak begitu baik, karena selalu menggunakan 16 ops untuk mengatur ulang
x
sebelum yang lain, dan 8, misalnya, dapat dicapai dalam 5 langkah.Menariknya, algoritma di atas tidak pernah menggunakan
y+=y
sama sekali, karenay
selalu dibuat aneh. Dalam hal ini, ia sebenarnya dapat menemukan program terpendek untuk rangkaian terbatas hanya 3 operasi.Pengujian
Saya menulis tes sederhana untuk memeriksa apakah solusi saya memang menghasilkan hasil yang benar, dan tidak pernah melewati 33 langkah, untuk semua input yang valid (
0 <= n < 65536
).Selain itu, saya mencoba melakukan analisis empiris untuk membandingkan output solusi saya terhadap output optimal - namun, ternyata pencarian pertama yang terlalu luas tidak efisien untuk mendapatkan panjang output minimum untuk setiap input yang valid
n
. Misalnya, menggunakan BFS untuk menemukan outputn = 65535
tidak berakhir dalam jumlah waktu yang wajar. Meskipun demikian, saya telah meninggalkanbfs()
dan terbuka untuk saran.Saya lakukan, bagaimanapun, menguji solusi saya sendiri terhadap @ CChak (diimplementasikan di Python di sini sebagai
U
). Saya perkirakan tambang saya akan menjadi lebih buruk, karena secara drastis tidak efisien untuk angka genap yang lebih kecil, tetapi rata-rata di seluruh jajaran dalam dua cara, tambang menghasilkan keluaran panjang rata-rata 10,8% hingga 12,3% lebih pendek. Saya pikir mungkin ini karena efisiensi yang lebih baik dari solusi saya sendiri pada angka ganjil, jadiV
gunakan milik saya pada angka ganjil dan @ CChak pada angka genap, tetapiV
ada di antara (sekitar 10% lebih pendek dariU
, 3% lebih lama dariS
).sumber
x,y='xy'
itu mungkin sampai sekarang. Sayangnya, saya tidak bisa memikirkan cara untuk menulis ulangc*b+e*2
secara ringkas dengan%
pemformatan.S(2)
keluarannya sangat panjang?S(2)
menjadi yang terpendek di 19). Saya tidak melacakx
dany
secara eksplisit, jadi meskipunx
mencapai 2 setelah langkah kedua, tetap berlanjut ke resetx
ke 0. Saya merasa seolah-olah harus ada solusi yang lebih baik, tetapi sampai sekarang saya tidak dapat memikirkan satu.