2-SAT
https://www.luogu.com.cn/problem/P4782
有 \(n\) 个布尔变量和 \(m\) 条约束,每条约束形如 \(a\lor b\),其中 \(a,b\) 是布尔方程,给每个布尔变量赋值使得所有约束成立.
把每个布尔变量拆成两个点,分别表示取 \(0\) 和取 \(1\),然后把约束条件翻译成图论语言.
因为 \(a\lor b \Leftrightarrow (\neg a \to b)\land(\neg b \to a)\),连 \(\neg a \to b\) 和 \(\neg b \to a\) 的边即可.
特别的,如果出现 \(a\land b\) 的约束,这相当于直接要求 \(a\) 和 \(b\) 为真,连 \(\neg a \to a\) 和 \(\neg b \to b\) 的边即可.
在构成有向图中,使用 \(tarjan\) 算法找 \(SCC\),如果某个布尔变量的两个点属于同一 \(SCC\),说明约束是不可能成立的,否则令拓扑序更大的变量元为真即可. 实际上,\(tarjan\) 算法求出的 \(SCC\) 为逆拓扑序.
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n,m;
cin >> n >> m;
int N = 2*n;
vector<vector<int>> adj(N+1);
for (int t=0;t<m;t++){
int i,a,j,b;
cin >> i >> a >> j >> b;
adj[i+(a^1?n:0)].push_back(j+(b?n:0));
adj[j+(b^1?n:0)].push_back(i+(a?n:0));
}
vector<int> dfn(N+1),low(N+1),belong(N+1);
vector<bool> in_stk(N+1,false);
stack<int> stk;
int tot = 1;
int timer = 1;
function<void(int)> dfs = [&](int u){
dfn[u] = low[u] = timer++;
in_stk[u] = true;
stk.push(u);
for (auto& v:adj[u]){
if (dfn[v]==0){
dfs(v);
low[u] = min(low[u],low[v]);
}
else if (in_stk[v]){
low[u] = min(low[u],dfn[v]);
}
}
if (dfn[u]==low[u]){
while (1){
int cur = stk.top();
stk.pop();
in_stk[cur] = false;
belong[cur] = tot;
if (cur==u) break;
}
tot++;
}
};
for (int i=1;i<=N;i++){
if (dfn[i]==0) dfs(i);
}
vector<int> res(n+1);
for (int i=1;i<=n;i++){
if (belong[i]==belong[i+n]){
cout << "IMPOSSIBLE" << '\n';
return;
}
if (belong[i]<belong[i+n]){
res[i] = 0;
}
else{
res[i] = 1;
}
}
cout << "POSSIBLE" << '\n';
for (int i=1;i<=n;i++){
cout << res[i] << ' ';
}
cout << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号