Самая длинная сеть домино


31

Описание задачи

Домино - это игра, в которую играют с тайлами с двумя значениями - одним слева, другим справа, например, [2|4]или [4|5]. Две плитки могут быть объединены вместе, если они содержат общее значение. Две плитки выше можно соединить так:

[2|4][4|5]

Последовательность nсоединенных плиток будем называть цепочкой длины n. Конечно, плитки можно поворачивать, так что плитки [1|2], [1|3]и [5|3]могут быть изменены в цепочку [2|1][1|3][3|5]длиной 3.

Учитывая список пар целых чисел, определите длину самой длинной цепочки, которая может быть сформирована с использованием этих плиток. Если список пуст, правильный ответ 0(обратите внимание, что вы всегда можете сформировать цепочку длины 1из непустого списка плиток).

Пример ввода / вывода

[(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!)
игру,

I guess it's P
l4m2

Ответы:


5

Брахилог , 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]], а затем сгладить / behead / unkknife, чтобы произвести [1:1:3:3:5:_](где _представляет неизвестное). Комбинация ~cи :{…l2}aэффективно разбивает это на группы из 2 элементов, и мы гарантируем, что все группы равны. Поскольку мы сгладили (удвоив длину), удалили один элемент из начала и добавили один в конце (без изменений) и сгруппировали в пары (вдвое уменьшив длину), он будет иметь ту же длину, что и исходная цепочка домино.

Инструкция «behead» завершится ошибкой, если на входе нет домино (фактически, IIRC :paтакже потерпит неудачу; aне нужны пустые списки), поэтому нам нужен особый случай для 0. (Одна большая причина, по которой мы имеем асимметрию между bи ~kпоэтому что нам также не нужен особый случай для 1.)


1
Боже мой, это намного короче ...
Fatalize

4

Брахилог , 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}...}]&]]]&

Я уверен, что играю в гольф. Но в основном тот же алгоритм, что и в ответе Брахилога Фатализ , с немного другим тестом в конце.


-1 байт: Differences/@Rest@Flatten@#~Partition~2вместо Differences/@Partition[Rest@Flatten@#,2]( Infixимеет более высокий приоритет, чем Map)
JungHwan Мин

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

Haskell , 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 байт

Golfed:

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, 198 183 байта

Обновление: улучшена обработка «максимально возможной пустой последовательности»

(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без элемента a, Mвозвращает максимум входных данных или 1.

Lявляется основной функцией, при вызове с одним аргументом генерирует все возможные начальные фрагменты и находит максимальную длину для каждого из них. При вызове с двумя аргументами lпервый элемент последовательности, которому должен соответствовать следующий фрагмент, Rявляется остальными частями.

Генерировать перестановки и «выбрать один элемент и разбить на остальное» было довольно сложно, чтобы реализовать в сжатой форме.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.