Rantai domino terpanjang

31

Deskripsi tantangan

Domino adalah permainan yang dimainkan dengan ubin dengan dua nilai di atasnya - satu di sebelah kiri, satu di sebelah kanan, misalnya [2|4]atau [4|5]. Dua ubin bisa digabung bersama jika mengandung nilai yang sama. Dua ubin di atas dapat digabungkan seperti ini:

[2|4][4|5]

Kami akan menyebut urutan nubin yang bergabung dengan rantai panjang n. Tentu saja, ubin bisa diputar, jadi ubin [1|2], [1|3]dan [5|3]bisa disusun ulang menjadi rantai [2|1][1|3][3|5]dengan panjang 3.

Diberikan daftar pasang bilangan bulat, tentukan panjang rantai terpanjang yang dapat dibentuk menggunakan ubin ini. Jika daftar kosong, jawaban yang benar adalah 0(perhatikan bahwa Anda selalu dapat membentuk rantai panjang 1dari daftar ubin yang tidak kosong).

Contoh input / output

[(0, -1), (1, -1), (0, 3), (3, 0), (3, 1), (-2, -1), (0, -1), (2, -2), (-1, 2), (3, -3)] -> 10
([-1|0][0|-1][-1|2][2|-2][-2|-1][-1|1][1|3][3|0][0|3][3|-3])

[(17, -7), (4, -9), (12, -3), (-17, -17), (14, -10), (-6, 17), (-16, 5), (-3, -16), (-16, 19), (12, -8)] -> 4
([5|-16][-16|-3][-3|12][12|-8])

[(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1)] -> 7
([1|1][1|1][1|1][1|1][1|1][1|1][1|1])

[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)] -> 1
(any chain of length 1)

[] -> 0
(no chain can be formed)
shooqie
sumber
Adakah batasan waktu atau memori berjalan? Pikirkan brute-forcing semua permutasi
Luis Mendo
3
@LuisMendo: Cukup yakin masalah ini NP, jadi jalankan O(n!)sesuai keinginan Anda
shooqie
I guess it's P
14m2

Jawaban:

5

Brachylog , 23 byte

s:papcb~k~c:{#=l2}al|,0

Cobalah online!

Penjelasan

s:papcb~k~c:{#=l2}al|,0
s                         Check subsets of the input (longest first).
 :pa                      Check all permutations inside the input's elements
    p                     and all permutations /of/ the input's elements.
     c                    Flatten the result;
      b                   delete the first element;
       ~k                 find something that can be appended to the end so that
         ~c               the result can be unflattened into
           :{    }a       a list whose elements each have the property:
             #=             all the elements are equal
               l2           and the list has two elements.
                   l      If you can, return that list's length.
                    |,0   If all else fails, return 0.

Jadi dengan kata lain, untuk input seperti [[1:2]:[1:3]:[5:3]], kami mencoba mengaturnya kembali menjadi rantai yang valid [[2:1]:[1:3]:[3:5]], kemudian ratakan / pangkas / hapuskan untuk menghasilkan [1:1:3:3:5:_](di mana _merupakan yang tidak diketahui). Kombinasi dari ~cdan :{…l2}asecara efektif membagi ini menjadi kelompok-kelompok 2 elemen, dan kami memastikan bahwa semua kelompok adalah sama. Saat kami meratakan (menggandakan panjang), menghapus satu elemen dari awal dan menambahkan satu di akhir (tidak ada perubahan), dan dikelompokkan menjadi berpasangan (membagi dua panjangnya), ini akan memiliki panjang yang sama dengan rantai domino asli.

Instruksi "pemenggalan" akan gagal jika tidak ada domino di input (sebenarnya, IIRC :pajuga akan gagal; atidak suka daftar kosong), jadi kita perlu kasus khusus untuk 0. (Satu alasan besar kita memiliki asimetri antara bdan ~kbegitu bahwa kita tidak perlu kasus khusus untuk 1.)


sumber
1
Ya ampun, itu jauh lebih singkat ...
Fatalkan
4

Brachylog , 29 byte

v0|sp:{|r}aLcbk@b:{l:2%0}a,Ll

Cobalah online!

Cukup yakin ini sangat panjang, tapi terserahlah. Ini juga sangat lambat.

Penjelasan

v0                               Input = [], Output = 0
  |                              Or
   sp:{|r}aL                     L (a correct chain) must be a permutation of a subset of the
                                   Input with each tile being left as-is or reversed
           Lcbk                  Concatenate L into a single list and remove the first and
                                   last elements (the two end values don't matter)
               @b                Create a list of sublists which when concatenated results in
                                   L, and where each sublist's elements are identical
                 :{     }a,      Apply this to each sublist:
                   l:2%0           It has even length
                           Ll    Output = length(L)

Alasan ini akan menemukan yang terbesar adalah karena s - subsetmenghasilkan poin pilihan dari subset terbesar ke terkecil.

Fatalisasi
sumber
4

Mathematica, 191 byte

If[#=={},0,Max[Length/@Select[Flatten[Rest@Permutations[#,∞]&/@Flatten[#,Depth[#]-4]&@Outer[List,##,1]&@@({#,Reverse@#}&/@#),1],MatchQ[Differences/@Partition[Rest@Flatten@#,2],{{0}...}]&]]]&

Bisa bermain golf sedikit, saya yakin. Tetapi pada dasarnya algoritma yang sama seperti pada jawaban Brachylog dari Fatalize , dengan tes yang sedikit berbeda pada akhirnya.

Greg Martin
sumber
-1 byte:, Differences/@Rest@Flatten@#~Partition~2alih-alih Differences/@Partition[Rest@Flatten@#,2]( Infixmemiliki prioritas lebih tinggi dari Map)
JungHwan Min
2

JavaScript (Firefox 30-57), 92 byte

(a,l)=>Math.max(0,...(for(d of a)for(n of d)if(!(l-n))1+f(a.filter(e=>e!=d),d[0]+d[1]-n)))
  • ladalah nilai terakhir, atau undefineduntuk doa awal. l-nOleh karena itu nilai yang salah jika domino dapat dimainkan.
  • d adalah domino yang dipertimbangkan.
  • nadalah akhir domino yang sedang dipertimbangkan untuk dirantai ke domino sebelumnya. Ujung lainnya dapat dengan mudah dihitung sebagai d[0]+d[1]-n.
  • 0, hanya menangani kasus dasar tidak ada kartu domino yang dapat dimainkan.
Neil
sumber
2

Haskell , 180 134 131 117 byte

p d=maximum$0:(f[]0d=<<d)
f u n[]c=[n]
f u n(e@(c,d):r)a@(_,b)=f(e:u)n r a++(f[](n+1)(r++u)=<<[e|b==c]++[(d,c)|b==d])

Cobalah online! Pendekatan baru ternyata lebih pendek dan lebih efisien. Alih-alih semua permutasi yang mungkin hanya semua rantai yang valid dibangun.

Sunting: Versi 117 byte jauh lebih lambat lagi, tetapi masih lebih cepat dari brute-force.


Metode gaya lama:

p(t@(a,b):r)=[i[]t,i[](b,a)]>>=(=<<p r)
p e=[e]
i h x[]=[h++[x]]
i h x(y:t)=(h++x:y:t):i(h++[y])x t
c%[]=[0]
c%((_,a):r@((b,_):_))|a/=b=1%r|c<-c+1=c:c%r
c%e=[c]
maximum.(>>=(1%)).p

Ini adalah implementasi brute-force yang mencoba semua permutasi yang mungkin (Jumlah permutasi yang mungkin tampaknya diberikan oleh A000165 , " faktorial ganda bilangan genap "). Cobalah secara online hanya mengelola input hingga panjang 7 (yang agak mengesankan karena 7 sesuai dengan 645120 permutasi).

Pemakaian:

Prelude> maximum.(>>=(1%)).p $ [(1,2),(3,2),(4,5),(6,7),(5,5),(4,2),(0,0)]
4
Laikoni
sumber
1

Python 2, 279 byte

Golf:

l=input()
m=0
def f(a,b):
 global m
 l=len(b)
 if l>m:m=l
 for i in a:
  k=a.index(i)
  d=a[:k]+a[k+1:]
  e=[i[::-1]]
  if not b:f(d,[i])
  elif i[0]==b[-1][1]:f(d,b+[i])
  elif i[0]==b[0][0]:f(d,e+b)
  elif i[1]==b[0][0]:f(d,[i]+b)
  elif i[1]==b[-1][1]:f(d,b+e)
f(l,[])
print m

Cobalah online!

Hal yang sama dengan beberapa komentar:

l=input()
m=0
def f(a,b):
 global m
 l=len(b)
 if l>m:m=l                      # if there is a larger chain
 for i in a:
  k=a.index(i)
  d=a[:k]+a[k+1:]                # list excluding i
  e=[i[::-1]]                    # reverse i
  if not b:f(d,[i])              # if b is empty
                                 # ways the domino can be placed:
  elif i[0]==b[-1][1]:f(d,b+[i]) # left side on the right
  elif i[0]==b[0][0]:f(d,e+b)    # (reversed) left side on the left
  elif i[1]==b[0][0]:f(d,[i]+b)  # right side on left
  elif i[1]==b[-1][1]:f(d,b+e)   # (reversed) right side on the right
f(l,[])
print m

Saya memposting karena saya tidak melihat jawaban python ... seseorang akan melihat jawaban saya dan, dengan jijik, dipaksa untuk memposting sesuatu yang jauh lebih pendek dan efisien.

Bobas_Pett
sumber
0

Clojure, 198 183 byte

Pembaruan: Penanganan yang lebih baik dari "urutan maksimum yang mungkin kosong"

(defn F[a C](remove(fn[i](identical? i a))C))(defn M[C](apply max 0 C))(defn L([P](M(for[p P l p](L l(F p P)))))([l R](+(M(for[r R[i j][[0 1][1 0]]:when(=(r i)l)](L(r j)(F r R))))1)))

Versi sebelumnya:

(defn F[a C](remove(fn[i](identical? i a))C))(defn M[C](apply max 1 C))(defn L([P](if(empty? P)0(M(for[p P l p](L l(F p P))))))([l R](M(for[r R[i j][[0 1][1 0]]:when(=(r i)l)](+(L(r j)(F r R))1)))))

Konvensi panggilan dan uji kasus:

(L [])
(L [[2 4] [3 2] [1 4]])
(L [[3, 1] [0, 3], [1, 1]])
(L [[17 -7] [4 -9] [12 -3] [-17 -17] [14 -10] [-6 17] [-16 5] [-3 -16] [-16 19] [12 -8]])
(L [[0 -1] [1 -1] [0 3] [3 0] [3 1] [-2 -1] [0 -1] [2 -2] [-1 2] [3 -3]])
(L [[1 1] [1 1] [1 1] [1 1] [1 1] [1 1] [1 1]])

Fmengembalikan elemen daftar Ctanpa elemen a, Mmengembalikan maksimal ingerer input atau 1.

Ladalah fungsi utama, ketika dipanggil dengan argumen tunggal ia menghasilkan semua potongan awal yang mungkin dan menemukan panjang maks untuk masing-masing. Ketika dipanggil dengan dua argumen, itu ladalah elemen pertama dari urutan yang cocok dengan bagian berikutnya dan Rsisanya dari potongan.

Menghasilkan permutasi dan "memilih satu elemen dan membelah untuk beristirahat" cukup sulit untuk diterapkan secara ringkas.

NikoNyrh
sumber