2-SAT - Алгоритмика
2-SAT

2-SAT

авторы Сергей Слотин Максим Иванов
пререквизиты Компоненты сильной связности

Ликбез. Конъюнкция — это «правильный» термин для логического «И» (обозначается \wedge или &). Конъюнкция возвращает true тогда и только тогда, когда обе переменные true.

Ликбез. Дизъюнкция — это «правильный» термин для логического «ИЛИ» (обозначается \vee или |). Дизъюнкция возвращает false тогда и только тогда, когда обе переменные false.

Рассмотрим конъюнкцию дизъюнктов, то есть «И» от «ИЛИ» от каких-то переменных или их отрицаний. Например, такое выражение:

(a | b) & (!c | d) & (!a | !b)

Если буквами: (А ИЛИ B) И (НЕ C ИЛИ D) И (НЕ A ИЛИ НЕ B).

Можно показать, что любую логическую формулу можно представить в таком виде.

Задача satisfiability (SAT) заключается в том, чтобы найти такие значения переменных, при которых выражение становится истинным, или сказать, что такого набора значений нет. Для примера выше такими значениями являются a=1, b=0, c=0, d=1 (убедитесь, что каждая скобка стала true).

В случае произвольных формул эта задача быстро не решается. Мы же хотим решить её частный случай — когда у нас в каждой скобке ровно две переменные (2-SAT).

#Графы импликаций

Казалось бы — причем тут графы? Заметим, что выражение aba | b эквивалентно (!ab)(!ba)(!a \rightarrow b) | (!b \rightarrow a). Здесь «\rightarrow» означает импликацию («если aa верно, то bb тоже верно»). С помощью этой подстановки приведем выражение к другому виду — импликативному.

Затем построим граф импликаций: для каждой переменной в графе будет по две вершины, (обозначим их через xx и !x!x), а рёбра в этом графе будут соответствовать импликациям.

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

Заметим, что если для какой-то переменной xx выполняется, что из xx достижимо !x!x, а из !x!x достижимо xx, то задача решения не имеет. Действительно: какое бы значение для переменной xx мы бы ни выбрали, мы всегда придём к противоречию — что должно быть выбрано и обратное ему значение.

Переформулируем данный критерий в терминах теории графов. Если из одной вершины достижима вторая и наоборот, то эти две вершины находятся в одной компоненте сильной связности. Тогда условие существования решения звучит так: для того, чтобы задача 2-SAT имела решение, необходимо, чтобы для любой переменной xx вершины xx и !x!x находились в разных компонентах сильной связности графа импликаций.

Оказывается, что это условие является не только необходимым, но и достаточным. Доказательством этого факта служит описанный ниже алгоритм.

#Алгоритм решения 2-SAT

Пусть решение существует, и нам надо его найти. Заметим, что для некоторых переменных может выполняться, что из xx достижимо !x!x или из !x!x достижимо xx (но не одновременно). В таком случае выбор одного из значений переменной xx будет приводить к противоречию, в то время как выбор другого — не будет. Чтобы выбирать из двух значений то, которое не приводит к возникновению противоречий, можно воспользоваться следующим простым правилом.

Правило. Пусть с[x]с[x] обозначает номер компоненты сильной связности, которой принадлежит вершина xx, причём номера упорядочены в порядке топологической сортировки компонент сильной связности: если есть путь из xx в yy, то c[x]c[y]c[x] \leq c[y]. Тогда, если c[x]>c[!x]c[x] > c[!x], то выбираем значение xx, иначе выбираем !x!x.

Докажем, что при таком выборе значений мы не придём к противоречию. Пусть, для определённости, c[x]>c[!x]c[x] > c[!x], и поэтому была выбрана вершина xx (для случая !x!x доказательство аналогичное).

  • Покажем, что из xx не достижимо !x!x. Так как номер компоненты сильной связности c[x]c[ x ] больше номера компоненты c[!x]c[ !x ], то компонента связности xx расположена «левее» компоненты связности !x!x, и из первой никак не может быть достижима последняя.
  • Покажем, что из любой вершины yy, достижимой из xx, недостижимо !y!y. Докажем от противного: пусть из xx достижимо yy, а из yy достижимо !y!y. Так как мы получали граф импликаций преобразованием (ab)((!ab)(!ba))(a | b) \leftrightarrow ((!a \rightarrow b) | (!b \rightarrow a)), и из xx достижимо yy, то из !y!y будет достижимо !x!x. Но, по предположению, из yy достижимо !y!y. Тогда мы получаем, что из xx достижимо !x!x, что противоречит условию.

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

Итак, мы построили алгоритм, который находит искомые значения переменных в предположении, что для любой переменной xx вершины xx и !x!x находятся в разных компонентах сильной связности:

  1. Построим граф импликаций, заменив все выражения вида aba | b двумя ребрами !ab!a \rightarrow b и !ba!b \rightarrow a.
  2. Найдем все компоненты сильной связности в графе импликаций.
  3. Проверим, что для любого значения xx его отрицание лежит в другой компоненте сильной связности: c[x]c[!x]c[ x ] \neq c[ !x ]. Если это не так, то решения не существует.
  4. Если требуется выводить ответ, то положим условие xx верным, если c[x]<c[!x]c[ x ] < c[ !x ], и неверным в противном случае.