2-SAT

SAT是是适定性(Satisfiability)问题的简称。一般形式为 k - 适定性问题,简称 k-SAT。而当k>2时该问题为 NP 完全的。

1|0定义


n 个布尔变量 x1xn,另有 m 个需要满足的条件,每个条件的形式都是 「xitrue / falsexjtrue / false」。比如 「x1 为真或 x3 为假」、「x7 为假或 x2 为假」。

(xixj)(¬xixj)

注意这里的或为排斥或

2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

2|0Tarjan SCC 缩点


把每个变量拆成两个点,X(True)X(False)。比如现在有一个要求X|Y=True,则把X(False)Y(True)连一条边,把X(True)Y(False)连一条边。连出来的图是对称的,然后跑一遍 Tarjan,如果存在某个变量的两个点在同一个强连通分量中的情况,则无解,否则有解。

构造方案时,我们可以通过缩点后的拓扑序确定变量的值。如果变量x的拓扑序在¬x之后,则取x为真,反之取x为假。注意 Tarjan 求得的 SCC 的编号相同与反拓扑序。

// luogu P4782 int32_t main() { int n, m, N; cin >> n >> m, N = n * 2 + 2; e.resize(N); dfn = inStk = low = scc = vector<int>(N); capacity.push_back(0); for (int i, a, j, b; m; m--) { cin >> i >> a >> j >> b; e[2 * i + (a ^ 1)].push_back(2 * j + b); e[2 * j + (b ^ 1)].push_back(2 * i + a); } for (int i = 2; i <= n * 2 + 1; i++) if (!dfn[i]) tarjan(i); vector<int> res(n + 1); for (int i = 1; i <= n; i++) { if (scc[i * 2] == scc[i * 2 + 1]) cout << "IMPOSSIBLE\n", exit(0); else if (scc[i * 2] > scc[i * 2 + 1]) res[i] = 1; } cout << "POSSIBLE\n"; for (int i = 1; i <= n; i++) cout << res[i] << " "; cout << "\n"; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/17652900.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示