最長のドミノチェーン


31

チャレンジの説明

Dominoesは、2つの値を持つタイルでプレイされるゲームです。1つは左側に、1つは右側に、たとえば[2|4]または[4|5]です。共通の値が含まれている場合、2つのタイルを結合できます。上記の2つのタイルは、次のように結合できます。

[2|4][4|5]

n結合されたタイルのシーケンスを、長さnのチェーンと呼びます。もちろん、タイルは回転できるため、タイル[1|2][1|3]および長さ3の[5|3]チェーン[2|1][1|3][3|5]に再配置できます。

整数のペアのリストを指定して、これらのタイルを使用して形成できる最長のチェーンの長さを決定します。リストが空の場合、正しい答えは01空でないタイルのリストからいつでも長さのチェーンを形成できることに注意してください)。

サンプル入出力

[(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)

実行時間またはメモリに制限はありますか?すべての順列をブルートフォースすることを考える
ルイスメンドー

3
@LuisMendo:この問題はNPであると確信しているので、O(n!)希望どおりに起動してください
-shooqie

I guess it's P
l4m2

回答:


5

Brachylog、23バイト

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

オンラインでお試しください!

説明

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.

つまり、のような入力の場合[[1:2]:[1:3]:[5:3]]は、有効なチェーンに再配置してから、[[2:1]:[1:3]:[3:5]]平坦化/頭首化/ unkknifeを生成して生成しようとします[1:1:3:3:5:_](ここで_、未知数を表します)。組み合わせ~cとは:{…l2}a効果的に2つの要素のグループにこれを分割し、そして我々は、すべてのグループが同じであることを確認します。フラット化(長さを2倍)、開始から1つの要素を削除し、最後に1つの要素を追加(変更なし)、ペアにグループ化(長さを半分)すると、これはドミノの元のチェーンと同じ長さになります。

入力にはドミノが存在しない場合は、「首を切る」命令は失敗します(実際には、IIRC :paも失敗します。a空のリストを嫌う)、我々は0(一つの大きな理由のための特別なケースを必要とするので、間に我々は非対称性を持っているbし、~kそうです1の特別なケースも必要ないことを確認してください)


1
ずっと短い
良さ

4

Brachylog、29バイト

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

オンラインでお試しください!

これが非常に長いことは確かですが、何であれ。これも非常に遅いです。

説明

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)

これが最大のものを見つける理由はs - subset、最大サブセットから最小サブセットまでの選択ポイントを生成するためです。


4

Mathematica、191バイト

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

かなりのゴルフができます、私は確信しています。しかし、基本的にはFatalizeのBrachylog answerと同じアルゴリズムで、最後にわずかに異なるテストがあります。


-1バイト:のDifferences/@Rest@Flatten@#~Partition~2代わりにDifferences/@Partition[Rest@Flatten@#,2](のInfix優先度が高いMap
ジョンファンミン

2

JavaScript(Firefox 30-57)、92バイト

(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)))
  • lは最後の値、またはundefined最初の呼び出し用です。l-nしたがって、ドミノをプレイできる場合は偽の値です。
  • d 検討中のドミノです。
  • nは、前のドミノへの連鎖を検討中のドミノの終わりです。もう一方の端はとして容易に計算できますd[0]+d[1]-n
  • 0, プレイ可能なドミノのないベースケースを単に処理します。

2

ハスケル180の134 131 117バイト

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])

オンラインでお試しください!新しいアプローチはより短く、より効率的であることが判明しました。すべての可能な順列の代わりに、すべての有効なチェーンのみが構築されます。

編集: 117バイトのバージョンは再びはるかに遅くなりますが、ブルートフォースよりも高速です。


古いブルートフォース法:

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

これは、可能なすべての順列を試行するブルートフォース実装です(可能な順列の数は、「偶数の二重階乗」であるA000165によって与えられるようです)。オンラインで試してみてください。長さ7までの入力をほとんど管理しません(7は645120の順列に対応するため、かなり印象的です)。

使用法:

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

1

Python 2、279バイト

ゴルフ:

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

オンラインでお試しください!

いくつかのコメントと同じこと:

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

pythonの回答が表示されなかったため、投稿しています...誰かが私の回答を表示し、うんざりして、もっと短くて効率的なものを投稿することを余儀なくされます。


0

Clojure、198183バイト

更新:「空のシーケンスの最大可能性」の処理が改善されました

(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)))

以前のバージョン:

(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)))))

呼び出し規約とテストケース:

(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]])

F要素のCないlist の要素aM返し、入力ingerの最大値または1を返します。

Lは、単一の引数で呼び出されると、すべての可能な開始ピースを生成し、それぞれの最大長を見つけるメイン関数です。2つの引数で呼び出された場合、lは、次のピースが一致する必要があるシーケンスの最初の要素であり、R残りのピースです。

順列の生成と「1つの要素の選択と残りの部分への分割」は、簡潔に実装するのが非常に困難です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.