2-SAT:
给定一个由布尔值组成的有 n 个元素的序列 A,再有若干限制,每个限制针对至多两个元素,求满足所有限制的序列 A 或者判定不存在。
常见的限制条件:
记每个限制条件给定
a
o
p
b
,
a
0
,
b
0
,
a
1
,
b
1
a~op~b,~a_0,~b_0,~a_1,~b_1
a op b, a0, b0, a1, b1 分别代表布尔取值为 0 或 1。
a
→
b
a\rightarrow b
a→b 代表 a 向 b 连边,表示由
a
a
a 推导出
b
b
b。
①
a
=
1
,
a
0
→
a
1
①~a=1,~a_0\rightarrow a_1
① a=1, a0→a1
a
=
0
,
a
1
→
a
0
~~~~~a=0,~a_1\rightarrow a_0
a=0, a1→a0
②
a
&
b
=
1
,
a
0
→
a
1
,
b
0
→
b
1
②~a~\&~b=1,~a_0\rightarrow a_1,~b_0\rightarrow b_1
② a & b=1, a0→a1, b0→b1
a
&
b
=
0
,
a
1
→
b
0
,
b
1
→
a
0
~~~~~a~\&~b=0,~a_1\rightarrow b_0,~b_1\rightarrow a_0
a & b=0, a1→b0, b1→a0
③
a
∣
b
=
1
,
a
0
→
b
1
,
b
0
→
a
1
③~a~\mid~b=1,~a_0\rightarrow b_1,~b_0\rightarrow a_1
③ a ∣ b=1, a0→b1, b0→a1
a
∣
b
=
0
,
a
1
→
a
0
,
b
1
→
b
0
~~~~~a~\mid~b=0,~a_1\rightarrow a_0,~b_1\rightarrow b_0
a ∣ b=0, a1→a0, b1→b0
④
a
⊕
b
=
1
,
a
0
→
b
1
,
a
1
→
b
0
,
b
0
→
a
1
,
b
1
→
a
0
④~a~\oplus b=1,~a_0\rightarrow b_1,~a_1\rightarrow b_0,~b_0\rightarrow a_1,~b_1\rightarrow a_0
④ a ⊕b=1, a0→b1, a1→b0, b0→a1, b1→a0
a
⊕
b
=
0
,
a
0
→
b
0
,
a
1
→
b
1
,
b
0
→
a
0
,
b
1
→
a
1
~~~~~a~\oplus b=0,~a_0\rightarrow b_0,~a_1\rightarrow b_1,~b_0\rightarrow a_0,~b_1\rightarrow a_1
a ⊕b=0, a0→b0, a1→b1, b0→a0, b1→a1
两种算法:
①
d
f
s
,
O
(
n
m
)
①~dfs,~O(nm)
① dfs, O(nm),实际上跑得飞快,可以求出字典序最小的解。
②
t
a
r
j
a
n
,
O
(
n
+
m
)
②~tarjan,~O(n+m)
② tarjan, O(n+m),强连通分量缩点,无解当且仅当存在
a
0
,
a
1
a_0,~a_1
a0, a1 在同一个强连通分量里。对于解的输出,缩点后,若
b
e
l
[
a
0
]
→
b
e
l
[
a
1
]
bel[a_0]\rightarrow bel[a_1]
bel[a0]→bel[a1],则选择
a
1
a_1
a1,即缩点后按反拓扑序构造解,而缩点后实则已经是反拓扑序,对于
a
0
,
a
1
a_0,~a_1
a0, a1 选择缩点后编号较小的一个即可。
相关题目:
https://vjudge.net/problem/HDU-1814 求字典序最小的解
https://vjudge.net/problem/HDU-4421 各种位运算限制建图
https://vjudge.net/problem/Gym-101987K
t
a
r
j
a
n
tarjan
tarjan 缩点输出解
参考代码:
#include<bits/stdc++.h> // HDU-1814
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
vector<int> G[maxn];
int vis[maxn], stk[maxn];
int n, m, top;
int dfs(int u){
if(vis[u ^ 1]) return 0;
if(vis[u]) return 1;
vis[u] = 1, stk[++top] = u;
for(int i = 0; i < sz(G[u]); ++i){
int v = G[u][i];
if(!dfs(v)) return 0;
}
return 1;
}
int bisat(){
for(int i = 0; i < n; ++i) vis[i] = 0;
for(int i = 0; i < n; ++i){
if(vis[i] || vis[i ^ 1]) continue;
top = 0;
if(!dfs(i)){
while(top) vis[stk[top--]] = 0;
if(!dfs(i ^ 1)) return 0;
}
}
return 1;
}
int main() {
while(scanf("%d%d", &n, &m) != EOF){
n <<= 1;
for(int i = 0; i < n; ++i) G[i].clear();
while(m--){
int x, y; scanf("%d%d", &x, &y);
--x, --y;
G[x].pb(y ^ 1), G[y].pb(x ^ 1);
}
for(int i = 0; i < n; ++i) sort(G[i].begin(), G[i].end());
int ret = bisat();
if(!ret) printf("NIE\n");
else{
for(int i = 0; i < n; ++i) if(vis[i]) printf("%d\n", i + 1);
}
}
return 0;
}
#include<bits/stdc++.h> // HDU-4421
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e3 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
vector<int> G[maxn];
int dfn[maxn], low[maxn], stk[maxn], ins[maxn], bel[maxn];
int b[maxn][maxn];
int tot, tim, top, n, m;
void tarjan(int u){
dfn[u] = low[u] = ++tim, stk[++top] = u, ins[u] = 1;
for(int i = 0; i < sz(G[u]); ++i){
int v = G[u][i];
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
int v; ++tot;
do v = stk[top--], ins[v] = 0, bel[v] = tot; while(v != u);
}
}
void init(){
for(int i = 0; i < n; ++i) G[i].clear(), dfn[i] = 0;
tot = tim = top = 0;
}
int solve(){
for(int i = 0; i < n; ++i) if(!dfn[i]) tarjan(i);
for(int i = 0; i < n; ++i) if(bel[i] == bel[i ^ 1]) return 0;
return 1;
}
int main() {
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
scanf("%d", &b[i][j]);
}
}
int ret = 1; m = n, n <<= 1;
for(int i = 0; i < 31; ++i){
init();
for(int j = 0; j < m; ++j){
for(int k = 0; k < m; ++k){
if(j == k) continue;
int t = (b[j][k] >> i) & 1;
int x = j << 1, y = k << 1;
if((j & 1) && (k & 1)){
if(t) G[x].pb(y ^ 1), G[y].pb(x ^ 1);
else G[x ^ 1].pb(x), G[y ^ 1].pb(y);
}
else if((~j & 1) && (~k & 1)){
if(t) G[x].pb(x ^ 1), G[y].pb(y ^ 1);
else G[x ^ 1].pb(y), G[y ^ 1].pb(x);
}
else{
if(t) G[x].pb(y ^ 1), G[x ^ 1].pb(y), G[y].pb(x ^ 1), G[y ^ 1].pb(x);
else G[x].pb(y), G[x ^ 1].pb(y ^ 1), G[y].pb(x), G[y ^ 1].pb(x ^ 1);
}
}
}
ret &= solve();
if(!ret) break;
}
printf("%s\n", ret ? "YES" : "NO");
}
return 0;
}
每人至少猜中两个,即至多猜错一个,设
a
,
b
,
c
a,~b,~c
a, b, c 分别为三次是否猜中,则
a
∣
b
=
1
,
a
∣
c
=
1
,
b
∣
c
=
1
a\mid b=1,~a\mid c=1,~b\mid c=1
a∣b=1, a∣c=1, b∣c=1。
#include<bits/stdc++.h> // Gym-101987K
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
vector<int> G[maxn];
int dfn[maxn], low[maxn], stk[maxn], ins[maxn], bel[maxn];
int tot, top, tim, n, m;
void tarjan(int u){
dfn[u] = low[u] = ++tim, stk[++top] = u, ins[u] = 1;
for(int i = 0; i < sz(G[u]); ++i){
int v = G[u][i];
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
int v; ++tot;
do v = stk[top--], ins[v] = 0, bel[v] = tot;
while(v != u);
}
}
void init(){
for(int i = 0; i < n; ++i) dfn[i] = 0, G[i].clear();
tot = tim = top = 0;
}
int solve(){
for(int i = 0; i < n; ++i) if(!dfn[i]) tarjan(i);
for(int i = 0; i < n; i += 2) if(bel[i] == bel[i ^ 1]) return 0;
return 1;
}
int main() {
scanf("%d%d", &n, &m);
n <<= 1, init();
while(m--){
int x, y, z; char sx[2], sy[2], sz[2];
scanf("%d%s%d%s%d%s", &x, sx, &y, sy, &z, sz);
--x, --y, --z, x <<= 1, y <<= 1, z <<= 1;
x |= sx[0] == 'B', y |= sy[0] == 'B', z |= sz[0] == 'B';
G[x ^ 1].pb(y), G[x ^ 1].pb(z);
G[y ^ 1].pb(x), G[y ^ 1].pb(z);
G[z ^ 1].pb(x), G[z ^ 1].pb(y);
}
int ret = solve();
if(!ret) printf("-1\n");
else{
for(int i = 0; i < n; i += 2) printf("%c", bel[i] < bel[i ^ 1] ? 'R' : 'B');
printf("\n");
}
return 0;
}