Representasi terpendek dari nomor Underload

13

Teks rasa

Esolang Underload berbasis stack memiliki ikatan yang menarik dengan pemrograman fungsional. Salah satunya adalah perlakuan terhadap datatype numerik — seperti kalkulus lambda, Anda mewakili bilangan alami N dengan fungsi yang melakukan tindakan N kali.

Untuk mempermudah, kami hanya akan mempertimbangkan hanya sebagian perintah Underload berikut:

  • : - Perintah ini menduplikasi item teratas di stack.
  • * - Perintah ini menggabungkan dua item teratas di stack menjadi satu item.

Kami mendefinisikan angka Underload N sebagai string :dan *yang, ketika dieksekusi, mengkonsumsi item teratas di stack, dan menghasilkan N salinan item yang digabungkan bersama-sama. Beberapa contoh:

  • Tidak ada angka Underload 0, -1, 1/2, π.
  • String kosong adalah angka Underload 1, karena membiarkan tumpukan tidak tersentuh.
  • :*adalah Underload numeral 2, karena menduplikasi item teratas, dan kemudian menggabungkan kedua salinan tersebut menjadi satu item: (A):*= (A)(A)*= (AA).
  • ::**adalah angka Underload 3: (A)::**= (A)(A):**= (A)(AA)*= (AAA).
  • :::*** adalah angka Underload 4.
  • :*:*juga merupakan angka Underload 4: (A):*:*= (AA):*= (AA)(AA)*= (AAAA).

Secara umum, Anda akan menemukan bahwa, jika Mdan Nadalah angka Underload M dan N, maka :N*adalah angka N +1, danMN merupakan angka M × N.

Tantangan

Tugas Anda adalah menulis program terpendek (mengambil input pada STDIN) atau fungsi (mengambil input melalui argumen) yang menghasilkan representasi terpendek dari angka Underload untuk inputnya sebagai string. Dengan kata lain, jika inputnya adalah bilangan asli positif N> 1, Anda harus menghasilkan angka N Underload yang panjang karakternya kurang dari atau sama dengan setiap Underload lainnya bilangan N.

Input dan output sampel: ("Input - OUTPUT.")

  • 1 - .
  • 2 - :* .
  • 5 - ::*:** (2 × 2 +1).
  • 7 - ::*::***(2 × 3 +1) atau:::**:** (3 × 2 +1).
  • 33 - ::*:*:*:*:** (2 × 2 × 2 × 2 × 2 + 1).
  • 49 - ::*:*:*:*::***(16 × 3 + 1, panjang 14) tetapi tidak ::*::***::*::***(7 × 7, panjang 16).

Jika inputnya bukan angka alami positif, Anda bebas untuk mengembalikan kesalahan, menghasilkan perilaku yang tidak terdefinisi, atau bahkan gagal menghentikannya. Penjelasan tentang metode kiriman Anda untuk menemukan jawabannya sangat dihargai.

Batasan celah jalan standar berlaku: tidak ada input tambahan, tidak ada permintaan web, nilai output / pengembalian harus tepat jawaban dan bukan aliran acak tak terbatas dari :dan *, dll.

algoritme hiu
sumber
@ Geobits Saya tidak mengatakan apa-apa tentang waktu eksekusi, jadi selama Anda dapat membuktikannya pada akhirnya akan memberikan jawaban yang benar, Anda baik.
algorithmshark
2
Masalah ini berkaitan dengan rantai tambahan; khusus, panjang jawaban yang benar untuk input xadalah di 2*A117498(x)mana A117498 memberikan kombinasi optimal metode biner dan faktor untuk menemukan rantai tambahan.
Peter Taylor

Jawaban:

4

GolfScript ( 61 60 55 54 53 karakter)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

Ini kurang rumit dari versi saya sebelumnya dan mengambil pendekatan yang sedikit berbeda, tetapi masih kasar. Kami tahu itu ':'X*'*'X*+adalah solusi kandidat, jadi jika kami menghasilkan semua string yang seimbang hingga panjang itu dan mengambil yang terpendek yang mengevaluasi ke hal yang benar, kami dapat yakin untuk menemukannya.

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

Terima kasih kepada Howard, dari solusinya saya telah mencuri beberapa tweak 1-char.

Peter Taylor
sumber
Haha, input dari 3 membutuhkan lebih dari tiga detik untuk dieksekusi di web interpreter. Golf terbaik.
algorithmshark
@algorithmshark, Anda dapat mempercepatnya sedikit dengan titik deduplikasi. Masukkan .&tepat setelah loop dalam (yaitu antara ~}%dan }*.
Peter Taylor
4

GolfScript ( 54 53 karakter)

Ini adalah pendekatan yang dalam semangat Howard (membangun string yang mengevaluasi ke nilai yang benar dan memilih yang terpendek, bukan kekerasan melalui kandidat string untuk menemukan mereka yang mengevaluasi ke nilai yang benar), tetapi cukup berbeda yang saya pikir itu termasuk dalam jawaban yang terpisah.

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

Demo online tidak tersedia karena menjalankan versi buggy dari interpreter.

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=
Peter Taylor
sumber
Dimungkinkan untuk mencukur satu dengan menggantinya 3+dengan )(mengeksploitasi fakta yang []0=tidak meninggalkan apa pun di tumpukan) jika tidak []2>menyebabkan kesalahan.
Peter Taylor
[]2>hasil []tanpa kesalahan.
Howard
@Howard, ah, golfscript.apphb.com harus menjalankan versi lama. Tetapi ternyata saya salah, karena penggantian itu menyebabkan mendapatkan input yang salah '1'.
Peter Taylor
Yang Anda dapat memperbaiki dengan ((=bukan -1=.
Howard
Dan golfscript.apphb.com memang menjalankan versi lama, contoh loop bersarang tidak berfungsi.
Howard
4

Python 2.7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

Penjelasan:
Ini adalah solusi yang sangat mudah. Ini secara rekursif menguji semua representasi yang mungkin dari n sebagai produk dari dua angka atau sebagai :(n-1)*, dan kemudian menemukan solusi panjang minimum. range (2, n) diperlukan agar rekursi telah membatasi kedalaman, dan n <2 memberikan case dasar.

Catatan:
i dan n / i adalah dua faktor dari n. Pengganti ... dan ... atau ... untuk ... jika ... yang lain ... tidak berfungsi karena '' dinilai salah. min string memberikan salah satu string terpendek. Python 2.7 menyimpan 1 karakter dengan menggunakan / bukannya //.

Sunting: Memindahkan casing dasar ke bagian belakang ekspresi, memungkinkan saya untuk menggunakan ... dan ... atau ... dan mencukur beberapa spasi.

Kasus uji:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'
isaacg
sumber
1
" min of string memberikan salah satu string terpendek " tidak benar, kecuali jika Anda memberikan argumen opsional key=len. Ini memberikan string paling awal secara leksikografis. ( Contoh ). Karena '*' < ':'ini berarti Anda memiliki bias terhadap solusi yang melibatkan kekuatan 2, tetapi apakah mereka selalu yang terpendek?
Peter Taylor
1
Jawab: sebenarnya bias lebih rumit, tetapi tidak selalu memberikan jawaban yang benar. Contoh tandingan terkecil adalah u(33), yang mana pengurutan leksikografis menghasilkan 14-char ::**::*::*:***tetapi memilah menurut panjangnya memberikan 12-char::*:*:*:*:**
Peter Taylor
1
Saya tidak pernah tahu tentang perbandingan string Python. Saya telah memperbarui jawaban saya.
isaacg
3

GolfScript, 63 58 56 karakter

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

Kode mengambil input pada STDIN dan mencetak hasilnya.

Contoh:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

Anda dapat menguji kasus Anda sendiri secara online .

Howard
sumber
Wow, saya pikir pendekatan berbasis anjak akan sedikit lebih lama daripada pendekatan brute force.
Peter Taylor
@PeterTaylor saya juga berpikir begitu tetapi ternyata bukan itu masalahnya. Selain itu, solusi brute force saya sedikit lebih lama dari milik Anda ;-)
Howard
Maukah Anda menjelaskan apa yang setiap porsi lakukan? Saya hanya bisa menindaklanjutinya sampai selesai :x(=. +1, karena dapat menjalankan 49 dalam jumlah waktu yang wajar.
algorithmshark
@algorithmshark Saya masih mengerjakan solusinya sehingga mungkin masih banyak berubah (seperti yang baru saja terjadi). Terutama, bagian x,2>{x\%!},memberikan semua pembagi sejati x, {.v=x@/v=+}/kemudian menggabungkan solusi untuk ddan x/duntuk semua pembagi d. {,}$mengurutkan mereka berdasarkan panjang dan 0=mengambil yang terpendek dari mereka (ditambah :(x-1)*kasus awal ).
Howard
2

Brachylog 2 , 30 (mungkin akhirnya 26) byte, tantangan tanggal bahasa

Berikut adalah fungsi yang berfungsi dengan implementasi Brachylog 2 saat ini (dan mengembalikan daftar kode karakter karena implementasi saat ini mengalami beberapa masalah dengan penanganan string):

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

Cobalah online!

Bahasanya masih sangat baru. Berikut adalah versi 26 byte dari program yang harus bekerja sesuai dengan spesifikasi, tetapi menggunakan beberapa fitur yang tidak diimplementasikan, dan dengan demikian belum valid, tetapi mungkin akan ada di masa depan (itu juga bahkan kurang efisien):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

Penjelasan

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

Ide dasarnya cukup sederhana: kami bergantian antara mendekomposisi angka menjadi (1 atau lebih) faktor (tidak harus faktor prima, tetapi faktor 1 tidak diperbolehkan), dan menyatakan masing-masing sebagai 1 + (representasi yang diperoleh dari rekursif panggilan). Ini dijamin untuk mencari semua kemungkinan representasi Underload dari angka (kita dapat menerapkan tahap perkalian "dua kali berturut-turut" dengan mengalikan bersama lebih dari 2 angka, dan tahap kenaikan dua kali berturut-turut melalui memisahkannya dengan tahap perkalian yang mengalikan bersama hanya satu nomor). Kita tidak memerlukan kasus dasar eksplisit, karena penguraian 1 menjadi faktor prima memberi kita daftar kosong, dan dengan demikian kita membangunnya dengan tahap perkalian yang mengalikan angka nol bersama-sama.

Program ini cukup tidak efisien, terutama karena petunjuk urutan evaluasi yang saya berikan (menghasilkan jawaban terpendek hingga terpanjang dalam hal ukuran output akhirnya), sementara memecahkan bagian "terpendek" dari pertanyaan, tidak terlalu bagus dalam hal sebenarnya membuat program selesai dengan cepat ( petunjuk yang jauh lebih berguna adalah "hanya menghasilkan jawaban terpendek pada setiap tahap rekursif", tetapi itu membutuhkan lebih banyak byte ...). Selain itu, ḋp~c×ᵐdapat menghasilkan partisi multiplikatif beberapa kali masing-masing, membuat program ini melakukan banyak pekerjaan yang berlebihan.


sumber
0

J - 81 char

Untuk anak cucu, ini adalah yang terbaik yang bisa saya lakukan di J.

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

Kami membuat daftar hasil, dimulai dengan dua string kosong (itu adalah ,~dan a:) mewakili 0 (tidak pernah digunakan) dan 1, dan kemudian iterasi kata kerja di atasnya (penggunaan licik kait, kereta api dan& ) yang menambahkan representasi terpendek nomor berikutnya.

Kata kerja aktual yang kita gunakan menggunakan panjang daftar sebagai indikator dari nomor apa kita beroperasi. Pertama, kami memfaktorkan angka ini menjadi pasangan faktor ( #(#~]-:"1<.)@(],.%)2}.i.@#), dan mengambil setiap pasangan dengan menarik dari array ( {~). Kami mengubah masing-masing pasangan (mungkin ada 0 dari mereka jika bilangan prima) menjadi string tunggal (<@;"1 ).

Lalu kami menambahkan ke daftar itu entri untuk hasil sebelumnya diurutkan dengan :dan *, dan mengurutkan daftar ini berdasarkan panjangnya ( (/:#&>)). Akhirnya, kami mengambil hasil pertama dari daftar ini ( 0{) dan menambahkannya ke akhir array basis ( [,). Ketika loop selesai iterasi, kami memiliki daftar panjang 2 lebih dari input, mulai dari 0. Jadi apa yang harus kami kembalikan adalah string next-to-last ( _2{::).

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539
algoritme hiu
sumber
0

Jelly , 33 byte, tantangan tanggal kiriman bahasa

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

Cobalah online!

Solusi brute force langsung.

Penjelasan

Program utama

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

Program utama menggunakan fungsi helper untuk menghitung semua cara yang mungkin untuk menghasilkan nilai melalui perkalian, kemudian mencoba menghasilkan nilai dengan penambahan, dan mengembalikan kemungkinan terpendek. Ini juga menangani kasus dasar (input dari1 ).

Fungsi pembantu

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

Fungsi helper mencoba semua metode yang mungkin untuk mengekspresikan input sebagai perkalian dua angka, dan saling memanggil program utama secara rekursif untuk mendapatkan representasi terpendek mereka.


sumber
0

GNU Prolog, 96 byte

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

Baris pertama adalah tata bahasa yang menerapkan evaluasi Underload, dan bekerja di arah sebaliknya (sebenarnya, itu tidak cukup bekerja di arah maju karena A#<Bkendala; ubah ini menjadi A#<Nuntuk program yang lebih lambat yang bekerja dua arah). Baris kedua mendefinisikan predikat seperti fungsis (yang merupakan fungsi yang diimplementasikan sebagai solusi untuk program ini) yang menemukan string sesingkat mungkin yang mengevaluasi ke angka yang diberikan sebagai input (ini dengan frustasi menyatakan untuk apa tugas yang relatif sederhana, tetapi itulah Prolog untuk Anda ...).

Program ini harus cukup jelas, mengingat bahwa itu lebih atau kurang merupakan terjemahan langsung dari spesifikasi ke tata bahasa, dan kemudian ke sintaksis Prolog; definisi vmengatakan bahwa Nadalah 1 dalam string kosong, atau Nmerupakan A× B(dengan Akurang dari Bkurang dariN ) dan string adalah gabungan dari v(A)dan v(B), atau Nadalah M+ 1 dan string adalah :concatenated dengan v(M)digabungkan dengan *. Baris kedua sedikit lebih halus;length(S,_) berarti "S memiliki panjang", tetapi menetapkan ini sebagai hal pertama di baris bertindak sebagai petunjuk untuk implementasi Prolog bahwa ia harus memeriksa panjang terpendek terlebih dahulu (yang berarti kita akan mendapatkan panjang terpendek yang mungkin untuk nilai pengembalian) .


sumber