Порахуйте максимальне розташування огорожі


9

Фон

Я хочу побудувати паркан. Для цього я зібрав купу жердин і приклеїв їх до землі. Я також зібрав багато дощок, які я прибиваю до стовпів, щоб зробити фактичний паркан. Я, як правило, захоплююсь будівельними матеріалами, і, швидше за все, я просто продовжуватиму прибивати дошки до стовпів, поки не знайдеться більше місця для їх розміщення. Я хочу, щоб ви перерахували можливі огорожі, якими я можу закінчитись.

Вхідні дані

Ваш вхід - це перелік двовимірних цілих координат, що представляють положення полюсів, у будь-якому зручному форматі. Ви можете припустити, що він не містить дублікатів, але ви не можете припустити нічого про його порядок.

Дошки представлені прямими лініями між стовпами, а для простоти ми вважаємо лише горизонтальні та вертикальні дошки. Дві полюси можуть бути з'єднані дошкою, якщо між ними немає інших стовпів або дощок, тобто дошки не можуть перетинатися один з одним. Розташування стовпів і дощок є максимальним, якщо до нього не можна додавати нових дощок (рівно, що між будь-якими двома полюсами з горизонтальним або вертикальним рівнем є або жердина, або дошка).

Вихідні дані

Ваш вихід - це кількість максимальних розташувань, які можна побудувати за допомогою полюсів.

Приклад

Розглянемо список вводу

[(3,0),(1,1),(0,2),(-1,1),(-2,0),(-1,-1),(0,-2),(1,-1)]

Якщо зверху подивитися, відповідне розташування жердин виглядає приблизно так:

  o
 o o
o    o
 o o
  o

Існує рівно три максимальних розташування, які можна побудувати за допомогою цих полюсів:

  o        o        o
 o-o      o|o      o-o
o----o   o||| o   o| | o
 o-o      o|o      o-o
  o        o        o

Таким чином, правильний вихід 3.

Правила

Ви можете написати або функцію, або повну програму. Виграє найменший байт, а стандартні лазівки заборонені.

Випробування

[] -> 1
[(0,0),(1,1),(2,2)] -> 1
[(0,0),(1,0),(2,0)] -> 1
[(0,0),(0,1),(1,0),(1,1)] -> 1
[(1,0),(0,1),(-1,0),(0,-1)] -> 2
[(3,0),(1,1),(0,2),(-1,1),(-2,0),(-1,-1),(0,-2),(1,-1)] -> 3
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1)] -> 3
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1),(0,-1)] -> 4
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(0,-1),(2,2)] -> 5
[(0,0),(4,0),(1,1),(1,-2),(3,1),(3,-2),(2,-1),(4,-1),(0,-1),(2,2)] -> 8

1
Здається, що приклад має двічі (-2,0). Чи повинен бути один із них (2,0)?
isaacg

@isaacg Насправді це має бути (0,-2), хороший улов. Зараз змінюється.
Згарб

Відповіді:


5

Математика, 301 байт

(t~SetAttributes~Orderless;u=Subsets;c=Complement;l=Select;f=FreeQ;Count[s=List@@@l[t@@@u[Sort@l[Sort/@#~u~{2},!f[#-#2&@@#,0]&]//.{a___,{x_,y_},{x_,z_},b___,{y_,z_},c___}:>{a,{x,y},b,{y,z},c}],f[#,t[{{a_,b_},{a_,c_}},{{d_,e_},{f_,e_}},___]/;d<a<f&&b<e<c]&],l_/;f[s,k_List/;k~c~l!={}&&l~c~k=={},{1}]])&

Це неназвана функція, яка приймає координати як вкладені Listі повертає ціле число. Тобто ви можете або дати йому ім’я та назвати його, або просто додати

@ {{3, 0}, {1, 1}, {0, 2}, {-1, 1}, {-2, 0}, {-1, -1}, {0, -2}, {1, -1}}

З відступом:

(
  t~SetAttributes~Orderless;
  u = Subsets;
  c = Complement;
  l = Select;
  f = FreeQ;
  Count[
    s = List @@@ l[
      t @@@ u[
        Sort @ l[
          Sort /@ #~u~{2}, 
          !f[# - #2 & @@ #, 0] &
        ] //. {a___, {x_, y_}, {x_, z_}, b___, {y_, z_}, c___} :> 
              {a, {x, y}, b, {y, z}, c}
      ],
      f[
        #,
        t[{{a_, b_}, {a_, c_}}, {{d_, e_}, {f_, e_}}, ___] 
          /; d < a < f && b < e < c
      ] &
    ], 
    l_ /; f[
      s, 
      k_List /; k~c~l != {} && l~c~k == {}, 
      {1}
    ]
  ]
) &

Я навіть не можу почати виражати, наскільки наївна ця реалізація ... це, безумовно, не могло бути більш жорстокою силою ...

  • Отримайте всі (не упорядковані) пари полюсів.
  • Сортуйте кожну пару та всі пари в канонічному порядку.
  • Відкиньте пари, які не ділять однієї координати (тобто не пов'язані ортогональною лінією).
  • Парочки відкидання можуть бути сформовані з двох коротших пар (щоб o--o--oвийшло лише два паркани замість трьох).
  • Отримати всі підмножини цих пар - тобто всі можливі комбінації парканів.
  • Відфільтруйте комбінації, що мають огорожі, що перетинаються.
  • Порахуйте кількість отриманих наборів парканів, для яких у списку не знайдено жодного суворого суперсета.

Дивно, але він вирішує всі тестові справи практично негайно.

Дійсно акуратний трюк, який я виявив для цього, - це використання Orderlessскорочення кількості шаблонів, з якими я повинен відповідати. По суті, коли я хочу скинути набори парканів з перехресною огорожею, мені потрібно знайти пару вертикальних і горизонтальних огорож і перевірити стан на них. Але я не знаю, в якому порядку вони з’являться. Оскільки шаблони списку зазвичай залежать від порядку, це призведе до двох дійсно довгих шаблонів. Тож замість цього я замінюю оточуючий список функцією tз t @@@- яка не визначена, тому вона тримається такою, якою вона є. Але ця функція є Orderless, тому я можу просто перевірити єдиний порядок у шаблоні, і Mathematica перевірить його проти всіх перестановок. Після цього я повертаю списки на місце List @@@.

Я хотів би, щоб вбудований, який є а) Orderless, б) не Listable і в) не визначений для 0 аргументів або аргументів списку. Тоді я міг би замінити tце. Але, схоже, такого оператора немає.


Коли ви думаєте, чи робить Mathematica це правильно чи досить швидко, відповідь - «так».
seequ

Ну, це настільки ж наївно, як і моя референтна реалізація. : П
Згарб

1

Haskell, 318 байт

import Data.List
s=subsequences
k[(_,a,b),(_,c,d)]|a==c=f(\w->(1,a,w))b d|1<2=f(\w->(2,w,b))a c
f t u v=[t x|x<-[min u v+1..max u v-1]]
q l=nub[x|x<-map(k=<<)$s[a|a@[(_,n,m),(_,o,p)]<-s l,n==o||m==p],x++l==nubBy(\(_,a,b)(_,c,d)->a==c&&b==d)(x++l)]
m=q.map(\(a,b)->(0,a,b))
p l=sum[1|x<-m l,all(\y->y==x||x\\y/=[])$m l]

Використання: p [(1,0),(0,1),(-1,0),(0,-1)]. Вихід:2

Як це працює:

  • створити всі підлісти списку вхідних даних та зберегти ті, що мають два елементи та мають однакові координати x або однакові y. Це перелік усіх пар жердин, де між ними можна побудувати паркан.
  • створити всі його списки
  • додайте дошки для кожного списку
  • видалити списки, де координата xy з’являється двічі (дошки та стовпи)
  • видалити дублікати списків (лише дошки) для обробки кількох порожніх списків через безпосередньо сусідніх полюсів (наприклад (1,0) та (1,1))
  • зберігайте ті, які не є суворим підпорядком іншого списку
  • порахуйте залишки списків
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.