Skip to content

Commit eabe3d5

Browse files
author
Xi Lin
committed
fix two sat
Change-Id: I4ee7bb11010924a960bc21f9eb76a532b216cb44
1 parent c410784 commit eabe3d5

19 files changed

+92
-49
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

GraphUtility/TwoSat.cc

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* 调用init()初始化, 传入变量个数, 节点标号必须从0开始
3+
* 调用add_edge()添加边, 调用add_var()添加变量的初始值
4+
* 调用solve()求解2sat 如果有解存在sol中
5+
* 对于变量x, x*2表示x, x*2+1表示~x, sol[x*2]表示x的值
6+
*
7+
* 使用tarjan算法求出强连通分量并染色,如果有一个布尔变量的原变量和反变量在一个scc中,那么原问题无解,否则一定存在解。
8+
*
9+
* 若求任意解,则对染色后的图重新建图,但是把边反向,统计入度,做拓扑排序,同时求出每个点反变量的颜色。
10+
* 之后按照拓扑排序的顺序,依次将对应scc标记为1以表示选中,其反变量对应的scc标记为2以表示不选中(也表示其反变量选中)。
11+
* 最后遍历一遍布尔变量的原变量和反变量:若变量所在的scc被标记为1,则表明选中变量;否则表示其另外一个变量被选中。
12+
*
13+
* 若求字典序最小的解,也使用标记法。对所有变量进行遍历,若 x_i 其原变量和反变量都没进行标记过,则dfs进去优先标记 x_i 的原变量,
14+
* 并根据他们连过的边,继续dfs标记。如果标记的过程中,某个变量的原变量和反变量同时被标记,则表示选中x_i的原变量无解,
15+
* 进而选中x_i的反变量继续标记。若在遍历过程中,发现无论标记某个遍历的原变量和反变量都无解,表示整个2-SAT无解。否则标记的就是字典序最小的解。
16+
*/
17+
#include <vector>
18+
#include <algorithm>
19+
20+
struct TwoSAT {
21+
static const int N = 200000 + 10;
22+
std::vector<int> edges[N];
23+
std::vector<int> scc[N];
24+
int low[N], dfn[N], col[N];
25+
int stk[N], top, cnt, sz;
26+
int sol[N];
27+
void init(int n) {
28+
this->n = n;
29+
for (int i = 0; i < n * 2; ++i) {
30+
edges[i].clear();
31+
}
32+
}
33+
void dfs(int x) {
34+
low[x] = dfn[x] = ++sz;
35+
stk[++top] = x;
36+
for (auto &y: edges[x]) {
37+
if (!dfn[y]) {
38+
dfs(y);
39+
low[x] = std::min(low[x], low[y]);
40+
}
41+
else if (col[y] == -1) {
42+
low[x] = std::min(low[x], dfn[y]);
43+
}
44+
}
45+
if (dfn[x] == low[x]) {
46+
SCC[cnt++].clear();
47+
do {
48+
SCC[cnt - 1].push_back(stk[top]);
49+
col[stk[top]] = cnt - 1;
50+
} while (stk[top--] != x);
51+
}
52+
}
53+
bool solve() {
54+
sz = top = cnt = 0;
55+
memset(dfn, 0, sizeof(*dfn) * n * 2);
56+
memset(col, -1, sizeof(*col) * n * 2);
57+
for (int i = 0; i < n * 2; ++i) {
58+
if (!dfn[i]) dfs(i);
59+
}
60+
for (int i = 0; i < n * 2; i += 2) {
61+
if (col[i] == col[i ^ 1]) return false;
62+
sol[i] = -1;
63+
}
64+
for (int i = 0; i < cnt; ++i) {
65+
int val = 1;
66+
for (auto &&x: scc[i]) {
67+
if (sol[x] == 0) val = 0;
68+
for (auto &&y: edges[x]) {
69+
if (sol[y] == 0) val = 0;
70+
}
71+
if (val == 0) break;
72+
}
73+
for (auto &&x: scc[i]) {
74+
sol[x] = val;
75+
sol[x ^ 1] = !val;
76+
}
77+
}
78+
return true;
79+
}
80+
void add_clause(int x, int xv, int y, int yv) {//x=xv or y=yv
81+
x = x << 1 | xv, y = y << 1 | yv;
82+
add_edge(x ^ 1, y);
83+
add_edge(y ^ 1, x);
84+
}
85+
void add_var(int x, int xv) { // x = xv
86+
x = x << 1 | xv;
87+
edges[x ^ 1].push_back(x);
88+
}
89+
void add_edge(int x, int y) {
90+
edges[x].push_back(y);
91+
}
92+
};
File renamed without changes.

graph-utility/TwoSat.cc

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)