Чи можете ви з'єднати точки?


18

Цей виклик базується на «Безкоштовному потоці». Інтернет-версію можна знайти тут: http://www.moh97.us/

Вам дадуть головоломку, і ви повинні повернутися, 1якщо головоломка вирішується, або 0якщо її немає.

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

Вас передають у розмірах квадрата, а потім x, y, c (де c - число, що представляє колір) кожної точки. Наприклад:

Якби вам 5,5 0,0,0 3,0,1 1,1,2 1,2,2 4,2,1 4,4,0було передано, це означало б:

0..1.
.2...
.2..1
....0

І має повернути 1.


Ось ще кілька тестових проблем:

5,2 2,0,1 0,1,2 4,1,2 представляє:

..1..
2...2

і не розв’язується, оскільки існує лише 1 1.

4,2 0,0,0 3,0,0 0,1,0 3,1,0 представляє:

0..0
0..0

і не вирішується, оскільки включає більше 2 0с.

8,6 0,0,1 7,5,1 представляє:

1.......
........
........
........
........
.......1

і не вирішується (як не можна використовувати кожен квадрат).

2,5 0,0,1 2,0,6 4,0,6 0,1,4 3,1,4 4,1,1 представляє:

1.6.6
4..41

і не вирішується, тому що ви не можете підключити 1s.

6,3 1,0,4 5,0,1 0,1,4 1,1,3 5,1,3 0,2,2 3,2,2 5,2,1 представляє:

.4...1
43...3
2..2.1

і не вирішується, оскільки ви не можете підключити 1 (або 3), оскільки два контури повинні обов'язково перетинатися.

5,2 0,0,1 3,0,1 0,1,3 4,1,1 представляє:

1..1.
3...3

і не вирішується, оскільки ви не можете використовувати всі квадрати при побудові шляху.

2,2 0,0,0 1,1,0 представляє:

1.
.1

і не вирішується, тому що ви також не можете використовувати всі квадрати

Ось ще кілька тестів:

5,5 0,3,0 0,4,1 1,2,2 1,3,1 2,0,0 3,0,4 3,1,2 3,3,5 3,4,4 4,4,5 повинен повернути 1

13,13 1,1,0 9,1,1 10,1,2 11,1,3 1,2,4 2,2,5 5,2,6 7,2,7 3,3,0 5,4,6 6,4,1 9,6,3 4,7,8 5,8,9 12,8,8 11,9,10 2,10,4 4,10,2 9,10,5 11,10,7 1,11,9 12,12,10 повинен повернути 1

7,7 0,0,0 0,1,1 1,1,2 2,1,3 4,2,4 0,3,1 5,3,3 0,4,4 2,4,5 5,4,2 0,5,0 1,5,5 3,5,6 3,7,6 має повернути 0


Це кодовий гольф, і застосовуються стандартні правила.


2
Чи рішення повинно бути "реально" правильним або просто теоретично правильним? Наприклад, простір стану можна розділити на призначення однієї з 6 можливих конфігурацій введення-вводу кожній порожній осередку. Розв’язаність легко визначається шляхом спробу всіх 6 ^ N комбінацій та повернення, 1якщо хтось із них відвідує всі комірки та з'єднує всі термінали. Очевидно, що цей підхід не завершиться за розумну кількість часу, окрім найменшої N(кількості порожніх комірок), але ми все ще маємо математичну гарантію, що алгоритм зрештою поверне правильне значення.
COTO

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

1
@NathanMerrill: Проблема зводиться до SAT і, таким чином, NP важко.
COTO

3
@NathanMerrill зменшення проблеми до SAT означає, що проблема полягає в NP, а не в тому, що вона NP-жорстка - це зведення SAT до проблеми, яка демонструє NP-твердість проблеми. Сторінка, на яку ви пов’язані, має посилання на доказ повноти NP.
karton_box

1
@VisualMelon Digit колір - це неправильне слово. Кожен колір представлений різною цифрою, а не цифрою.
Натан Меррілл

Відповіді:


3

Хаскелл

import Data.List.Split
import qualified Data.Sequence as Q
import Data.List
import Control.Monad

data A a = S a | E a | P a | X deriving Eq

sc = foldr1 (Q.><)
sp b x y p = Q.update y (Q.update x p $ b `Q.index` y) b
dt b c | S c `elem` sc b = E c
       | otherwise = S c
ad b [x, y, c] = sp b x y (dt b c)

ep b [x, y, c] = do
  let nps = filter ob [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
      ns = map gp nps
  [b | E c `elem` ns] ++ do
    (x', y') <- filter ((== X) . gp) nps
    ep (sp b x' y' (P c)) [x', y', c]
  where ob (u, v) = 0 <= u && u < length (b `Q.index` 0) && 0 <= v && v < length b
        gp (u, v) = b `Q.index` v `Q.index` u

rd i = let [c, r] : ps = (map read . splitOn ",") <$> words i :: [[Int]]
           e = Q.replicate r $ Q.replicate c X
           cs = map last ps
           ss = nubBy (\[_,_,c1] [_,_,c2] -> c1 == c2) ps
           b = foldl ad e ps
           bs = foldM ep b ss
       in if even (length cs) && length ss == length cs `div` 2 &&
             (all (\[j,k] -> j==k) . chunksOf 2 . sort $ cs) &&
             any (null . Q.elemIndicesL X . sc) bs
           then 1
           else 0

main = rd <$> getContents >>= print

Ключ

  • sc: Seq concat
  • sp: встановлення положення
  • dt: тип крапки (тобто початок або кінець рядка)
  • оголошення: додайте крапку
  • ep: продовжити шлях
  • rd: запустіть точки (первинний чистий алгоритм)

2
Дякуємо за подання та ласкаво просимо до обміну стеками PPCG. Це кодове завдання для гольфу, тобто метою є написання найкоротшої програми, яка вирішує проблему. Ви ведете себе за те, що у вас єдина відповідь, але ви повинні спробувати максимально скоротити свою програму.
isaacg

Я чесно вражений, що ти відповів на це питання після цього часу. Також ця проблема була скоріше викликом коду, але я використовував код-гольф, оскільки важко було придумати іншу бальну оцінку.
Натан Меррілл

Так, я не надто переймався аспектом "гольфу"; Я намагаюся навчитися Haskell, і це здалося цікавою проблемою :-)
Метт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.