Общая проблема SAT (булева выполнимость) является NP-полной. Но 2-СБ , где каждое предложение имеет только две переменные, в P . Напишите решатель для 2-SAT.
Входные данные:
Экземпляр 2-SAT, закодированный в CNF следующим образом. Первая строка содержит V, число булевых переменных и N, количество предложений. Затем следуют N строк, каждая с 2 ненулевыми целыми числами, представляющими литералы предложения. Положительные целые числа представляют данную логическую переменную, а отрицательные целые числа представляют отрицание переменной.
Пример 1
вход
4 5
1 2
2 3
3 4
-1 -3
-2 -4
который кодирует формулу (х 1 или х 2 ) и (х 2 или х 3 ) и (х 3 или х 4 ) и (не х 1 или не х 3 ) и (не х 2 или не х 4 ) .
Единственная установка из 4 переменных, которая делает всю формулу истинной, это x 1 = false, x 2 = true, x 3 = true, x 4 = false , поэтому ваша программа должна вывести одну строку
выход
0 1 1 0
представляющие значения истинности переменных V (в порядке от x 1 до x V ). Если существует несколько решений, вы можете вывести любое их непустое подмножество, по одному на строку. Если нет решения, вы должны вывести UNSOLVABLE
.
Пример 2
вход
2 4
1 2
-1 2
-2 1
-1 -2
выход
UNSOLVABLE
Пример 3
вход
2 4
1 2
-1 2
2 -1
-1 -2
выход
0 1
Пример 4
вход
8 12
1 4
-2 5
3 7
2 -5
-8 -2
3 -1
4 -3
5 -4
-3 -7
6 7
1 7
-7 -1
выход
1 1 1 1 1 1 0 0
0 1 0 1 1 0 1 0
0 1 0 1 1 1 1 0
(или любое непустое подмножество этих 3 строк)
Ваша программа должна обрабатывать все N, V <100 за разумное время. Попробуйте этот пример, чтобы убедиться, что ваша программа может обрабатывать большие экземпляры. Самая маленькая программа выигрывает.
Ответы:
Haskell, 278 символов
Не грубая сила. Работает за полиномиальное время. Быстро решает сложную проблему (60 переменных, 99 предложений):
И на самом деле, большая часть этого времени уходит на компиляцию кода!
Полный исходный файл с тестовыми и быстрой проверки тестов доступны .
Ungolf'd:
В версии golf'd,
satisfy
иformat
были свернутый вreduce
, хотя для того , чтобы избежать прохожденияn
,reduce
возвращает функцию из списка переменных ([1..n]
) в результате строки.s
оператор, лучшая обработка новой строки∮
в качестве оператора!★
поэтому тест теперь переименован∈
источник
J
119103Проходит все тестовые случаи. Нет заметного времени выполнения.Изменить: Устранено
(n#2)
и, таким образомn=:
, а также устранение некоторых рангов (спасибо, isawdrones). Tacit-> явный и двоичный-> монадический, исключая еще несколько символов каждый.}.}.
к}.,
.Редактировать: Упс. Это не только не решение для большого N, но
i. 2^99x
-> «ошибка домена», чтобы добавить оскорбление глупости.Вот оригинальная версия без краткости и краткое объяснение.
input=:0&".;._2(1!:1)3
сокращает ввод на новых строках и анализирует номера в каждой строке (накапливая результаты во ввод).n
, матрица предложений назначаетсяclauses
(не требуется счетчик предложений)cases
0..2 n -1 преобразуется в двоичные цифры (все тестовые случаи)(Long tacit function)"(_,1)
применяется для каждого случая вcases
со всемиclauses
.<:@|@[{"(0,1)]
получает матрицу операндов предложений (беря abs (op number) - 1 и разыменовывая из case, который является массивом)*@>:@*@[
получает неправильный массив битов «not not» (0 для not) через злоупотребление signum.=
применяет не биты к операндам.[:*./[:+./"1
применяется+.
(и) ко всем строкам результирующей матрицы и*.
(или) ко всем результатам этого.*@+/
применяется к результатам дает 0, если есть результаты и 1, если их нет.('UNSOLVABLE'"_)
`(#&cases) @.(*@+/) results
запускает постоянную функцию, дающую UNSOLVABLE, если 0, и копию каждого элемента 'solution', если 1.echo
волшебные отпечатки результата.источник
"(_,1)
к"_ 1
.#:
будет работать без левого аргумента.К - 89
Тот же метод, что и у решения J
источник
Рубин, 253
Но это медленно :(
Довольно читабельно, когда развернуто:
источник
OCaml + Батареи,
438436 символовТребуется комплект батарей OCaml верхнего уровня:
Должен признаться, это прямой перевод решения Haskell. В своей защите, что в своей очереди , является прямым кодированием алгоритма , представленной здесь [PDF], с обоюдными
satisfy
-eliminate
рекурсиями свернутой в одну функцию. Необъясненная версия кода, за вычетом использования батарей, выглядит так:(
iota k
каламбур, я надеюсь, вы простите).источник