2-SAT

2-SATを解きます。 変数 x0,x1,,xN1x_0, x_1, \cdots, x_{N - 1} に関して、

というクローズを足し、これをすべて満たす変数の割当があるかを解きます。

コンストラクタ

two_sat ts(int n)

nn 変数の2-SATを作ります。

制約

計算量

add_clause

void ts.add_clause(int i, bool f, int j, bool g)

(xi=f)(xj=g)(x_i = f) \lor (x_j = g) というクローズを足します。

制約

計算量

satisfiable

bool ts.satisfiable()

条件を足す割当が存在するかどうかを判定する。割当が存在するならばtrue、そうでないならfalseを返す。

制約

計算量

足した制約の個数を mm として

answer

vector<bool> ts.answer()

最後に呼んだ satisfiable の、クローズを満たす割当を返す。satisfiable を呼ぶ前や、satisfiable で割当が存在しなかったときにこの関数を呼ぶと、中身が未定義の長さ nn の vectorを返す。

計算量

使用例

AC code of https://atcoder.jp/contests/practice2/tasks/practice2_h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <atcoder/twosat>
#include <iostream>
#include <vector>
using namespace std;
using namespace atcoder;
int main() {
int n, d;
cin >> n >> d;
vector<int> x(n), y(n);
for (int i = 0; i < n; i++) {
cin >> x[i] >> y[i];
}
// ts[i] = (i-th flag is located on x[i])
two_sat ts(n);
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (abs(x[i] - x[j]) < d) {
// cannot use both of x[i] and x[j]
ts.add_clause(i, false, j, false);
}
if (abs(x[i] - y[j]) < d) {
ts.add_clause(i, false, j, true);
}
if (abs(y[i] - x[j]) < d) {
ts.add_clause(i, true, j, false);
}
if (abs(y[i] - y[j]) < d) {
ts.add_clause(i, true, j, true);
}
}
}
if (!ts.satisfiable()) {
cout << "No" << endl;
return 0;
}
cout << "Yes" << endl;
auto answer = ts.answer();
for (int i = 0; i < n; i++) {
if (answer[i])
cout << x[i] << endl;
else
cout << y[i] << endl;
}
return 0;
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX