Hasilkan urutan Skolem

10

Urutan skolem

Sebuah Skolem urutan adalah urutan 2nnomor di mana setiap nomor iantara 1dan nterjadi tepat dua kali, dan jarak antara dua kejadian ipersis ilangkah. Berikut adalah beberapa contoh urutan Skolem:

1 1
1 1 4 2 3 2 4 3
16 13 15 12 14 4 7 3 11 4 3 9 10 7 13 12 16 15 14 11 9 8 10 2 6 2 5 1 1 8 6 5

Urutan berikut bukanlah urutan Skolem:

1 2 1 2      (The distance between the 1's is 2, not 1)
3 1 1 3      (The number 2 is missing)
1 1 2 1 1 2  (There are four 1's)

Objektif

Tulis program, fungsi, atau ekspresi untuk menghitung jumlah semua urutan Skolem dengan panjang tertentu. Secara lebih eksplisit, input Anda adalah bilangan bulat n, dan output Anda adalah jumlah urutan panjang Skolem 2n. Urutan ini memiliki entri OEIS . Untuk n = 0, Anda dapat mengembalikan salah satu 0atau 1. Beberapa nilai pertama, mulai dari 0, adalah

0, 1, 0, 0, 6, 10, 0, 0, 504, 2656, 0, 0, 455936, 3040560, 0, 0, 1400156768

Aturan dan penilaian

Ini golf kode. Format output lemah karena alasan.

stan
sumber
Hanya ingin tahu, tetapi apa yang ada 0, 1, 0, 0, 6...di pertanyaan Anda? Apakah itu cuplikan kode, jika demikian bahasa apa itu?
PhiNotPi
2
Mengapa item pertama di output Anda 0? Jika Anda akan mengaku 0sebagai input yang valid maka output seharusnya 1.
Peter Taylor
1
Beberapa (termasuk kode saya) percaya bahwa tidak ada urutan kosong. Jika saya membuat Anda merasa lebih baik, kembalikan.
Stanby
2
AFAIK dalam setiap konteks Anda mengasumsikan ada satu dan hanya satu urutan kosong / objek nol / set kosong dll / fungsi-ke / dari-set-kosong / grafik kosong / apa pun.
Bakuriu
1
@ Bromby, apa kau baru saja menyebut Knuth bodoh?
Peter Taylor

Jawaban:

8

GolfScript, 48 46 karakter

:b,1,{)2\?){{.2$&!{.2$|@@}*.+.4b?<}do;;}+%}@/,

Versi yang lebih cepat ( coba online ) - berjalan dengan cepat, mis. n=8Membutuhkan waktu sekitar dua detik. Dan pendekatan yang dipilih hanya membutuhkan sedikit karakter.

Versi ini juga berfungsi dengan bitmask. Ini membangun array hasil yang mungkin dari 1 ke atas, yaitu untuk n=3:

1: 000011        000110 001100 011000 110000
2: 010111 101011 101110        011101 110101 111010

Sementara beberapa hasil (seperti 000011) memiliki dua kemungkinan lanjutan, yang lain (yaitu 001100) tidak memiliki dan dihapus dari array hasil.

Penjelasan kode:

:b           # save the input into variable b for later use
,            # make the list 0..b-1 (the outer loop)
1,           # puts the list [0] on top of the stack - initially the only possible
             # combination
{)           # {...}@/ does the outer loop counting from i=1 to b
  2\?)       # computes the smalles possible bit mask m=2^i+1 with two bits set 
             # and distance of those equal to i (i.e. i=1: 11, i=2: 101, ...)
  {          # the next loop starts with this bitmask (prepended to code via
             # concatination {...}+
             # the loop itself iterates the top of the stack, i.e. at this point 
             # the result array                 
             # stack here contains item of result array (e.g. 00000011)
             # and bitmask (e.g. 00000101)
    {        # the inner-most loop tries all masks with the current item in the result set
      .2$&!  # do item and result set share not single bit? then - {...}*
      {
        .2$| # then generate the new entry by or-ing those two
        @@   # push it down on the stack (i.e. put working items to top)
      }*
      .+     # shift the bit mask left by one
      .4b?<  # if still in the range loop further
    }do;;    # removes the remainders of the loop (i.e. item processed and mask)
  }+%        # stack now contains the new result array
}@/
,            # length of result array, i.e. the number of Skolem sequences
Howard
sumber
Menerima solusi terikat yang lebih cepat.
Stanby
6

Ekspresi J, 47 karakter

 +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y

Contoh:

    y=:5
    +/*/"1((=&{:+.2-#@])#;.2)\"1~.(i.!+:y)A.,~>:i.y
10

Butuh sekitar 30 detik untuk y=:5di mesin saya.

Algoritma ini sangat lambat:

  • ~.(i.!+:y)A.,~>:i.ymenghasilkan setiap permutasi 1 2 .. y 1 2 .. ydan menghapus entri duplikat
  • ((=&{:+.2-#@])#;.2)\"1 menghitung:
    • (...)\"1 untuk setiap awalan dari setiap baris:
      • #;.2 menghitung elemen sebelum setiap kemunculan elemen terakhir
      • #@] menghitung jumlah penghitungan (yaitu jumlah kemunculan elemen terakhir)
      • =&{: menentukan "kesetaraan" "dari" "elemen terakhir" dari daftar hitungan dan daftar asli.
      • +.adalah OR logis. =&{:+.2-#@]berbunyi "elemen terakhir [dari daftar hitungan dan daftar asli] sama, atau hanya ada satu elemen [dalam daftar hitungan] daripada dua".
  • */"1 mengalikan (logis DAN) di atas baris tabel kondisi, menentukan permutasi yang merupakan urutan Skolem.
  • +/ menjumlahkan yang dan nol bersama-sama.
John Dvorak
sumber
6

GolfScript (46 karakter)

:&1,\,{0,2@)?)2&*{2${1$^}%@+\2*}*;+}/{4&?(=},,

Ini adalah ekspresi yang mengambil input pada stack. Untuk mengubahnya menjadi program lengkap yang mengambil input pada stdin, prepend~

Ini cukup tidak efisien - sebagian besar penghematan yang saya lakukan dalam bermain golf turun dari 56 karakter yang tidak diserang adalah dengan memperluas rentang loop dengan cara yang tidak memberikan hasil yang salah tetapi melakukan perhitungan limbah.

Pendekatannya adalah penyembunyian bitwise produk Cartesian. Misalnya (menggunakan biner untuk topeng) untuk n=4kode yang tidak diklik akan menghitung xor dari setiap elemen dalam produk Cartesian [00000011 00000110 ... 11000000] x [00000101 00001010 ... 10100000] x ... x [00010001 ... 10001000]. Hasil apa pun dengan 8 bit hanya dapat dicapai dengan masker yang tidak tumpang tindih.

Untuk mengoptimalkan ukuran daripada kecepatan, kode mengakumulasikan produk parsial ( S1 u S1xS2 u S1xS2xS3 ...) dan membuat setiap produk menjadi 2nelemen bukan hanya 2n-1-iyang sebenarnya dapat berkontribusi pada urutan yang valid.

Kecepatan

Versi golf berjalan selama n=510 detik di komputer saya, dan lebih dari 5 menit untuk n=6. Versi ungolfed asli menghitung n=5dalam waktu kurang dari satu detik, dan n=6dalam waktu sekitar 1 menit. Dengan filter sederhana pada hasil antara, ia dapat menghitung n=8dalam 30 detik. Saya telah memasukkannya ke 66 karakter (sebagai program - 65 karakter sebagai ekspresi) sambil menjaga agar loop tetap dibatasi dan memfilter tabrakan antara:

~:&1,\,{0,\).2\?)2&*@-{.{[\].~^.@~+<{;}*}+3$%@+\2*}*;\;}/{4&?(=},,
Peter Taylor
sumber
Sial. Tepat ketika saya berpikir solusi 48char J saya cukup bagus untuk diposting.
John Dvorak
Sial. Ikatan 47 karakter kami tidak bertahan lama. +1
John Dvorak
5

GolfScript, 49 karakter

~:/..+?:d(,{d+/base(;:w;/,{.w?)w>1$?=},,/=},,/1=+

Mengharapkan nomor ndi STDIN. Ini kode-golf - jangan coba kode dengan nlebih dari 5.

Howard
sumber
Aduh, tidak lebih dari 5?
Stanby
@ bbyby Ini adalah upaya langsung pertama. Kita sering harus mengambil kecepatan keputusan vs ukuran - dan kode-golf adalah tentang ukuran. Itu sebabnya saya juga menambahkan versi cepat - yang awalnya jauh lebih lama tapi sekarang bahkan lebih pendek.
Howard
0

Sage, 70

Ini sedikit lebih pendek dari aslinya.

sum(1for i in DLXCPP([(i-1,j,i+j)for i in[1..n]for j in[n..3*n-i-1]]))

Bagaimana itu bekerja:

Diberikan matriks 0/1, masalah sampul yang tepat untuk matriks itu adalah menemukan subset dari baris yang dijumlahkan (sebagai bilangan bulat) ke vektor semua-yang. Sebagai contoh,

11001
10100
01001
00011
00010

punya solusinya

10100
01001
00010

Pendekatan favorit saya untuk masalah adalah melemparkannya ke masalah sampul yang tepat. Urutan skolem secara efisien memfasilitasi ini. Saya membuat masalah sampul yang tepat di mana solusi berada di bijection dengan urutan panjang Skolem 2n. Misalnya, deretan masalah n=6adalah

  a   |  b  
001000|001001000000 # S[b] = S[b+a+1] = a

di mana 1 dalam posisi a < nberarti simbol ayang digunakan. Posisi yang tersisa sesuai dengan lokasi aktual dalam urutan. Sampul yang tepat sesuai dengan setiap simbol yang digunakan tepat sekali, dan setiap lokasi diisi tepat sekali. Dengan konstruksi, simbol apa pun kdi lokasi berjarak kjauh dari mitranya.

Dalam Sage, DLXCPPadalah implementasi "link menari" - ini memecahkan masalah sampul yang tepat dengan cara yang sangat anggun. Ini adalah salah satu algoritma favorit saya, dan berada tepat di permukaan Sage membuat enumerasi kombinatorial menyenangkan.

stan
sumber
Wow, link menari. Gunakan len(list(...))akan menghemat 4 karakter.
Ray
@ Ray Komputer saya akan mati jika saya menghitung len(list(...))n = 16. Dan itu akan benar-benar membunuh runtime.
Stanby
Itu benar, karena mengubah generator menjadi daftar membutuhkan banyak memori.
Ray