【学习笔记】 2-SAT问题

Description

\(2-SAT\)问题就是给定一串变量,每个变量只能为真或假。

要求对这些变量进行赋值,满足方程所代表的限制条件,\(\rm 2-sat\) 问题中的限制是只与两个变量有关的,形如 $x_1 || x_2 \(,\)x_1 && (!x_2)$

如果这个条件变成三或者三以上个\(x\)相关的了,就只能\(2^n\)枚举了,即 \(N-SAT\) 问题是 \(NP\) 完全

Solution

首先将每个点拆成两个表示其为真或者为假,这里使用 \(i\) 表示这个点真点,\(i'\) 表示假点

问题中的图上的每条边 \((u,v)\) 表示如果 \(u\) 所代表的情况发生了,\(v\) 所代表的情况也要发生,举例而言即形如 \(x || y\) 的限制 则连 \((x',y),(y',x)\) 即如果 \(x\) 假了则 \(y\) 必须真

而题目中的限制也常可以表示成或而不是与的形式,建图时另外一个需要注意的点就是连接表示逆否命题的边

之后 \(tarjan\) 求强连通分量,如果有 scc[i]==scc[i+n] 则无解,原因是同一个强连通分量里面的点表示一个情况的并集,一个点的真假性是唯一的

对于求解 bool 方程每个变量的解,结论是 x_i=[scc[i]<scc[i+n]]

如果 \(x_i\) 可以到达 \(x'_i\) 但是反向不行,那么只能选择 \(x'_i\),也就是其所在的强连通分量在拓扑序上排名较后的一个

这时候可以踩在巨人 \(\rm tarjan\) 的肩膀上:使用 \(\rm scc\) 序是拓扑序的逆序这一结论得到答案

例题

NEERC2016 Binary Code

前后缀优化建图+ \(2-sat\) 模板题,在 这篇博客 中已经有写到

JSOI2019 精准预测

(其实写这篇博客就是为了写这题题解)

将每个火星人在每个时间存在与否建立 \(2\times n(T+1)\) 个点,根据实际含义,每个人本身在 \(i\) 时刻存活则在 \(i-1\) 时刻存活,在 \(i\) 时刻死亡则在 \(i+1\) 时刻死亡

再根据实际含义,对于操作一,如果 \(y\)\(i+1\) 存活则 \(x\)\(i\) 存活,也要连逆否命题

对于操作二,\(y\)\(i\) 时刻存活则对应 \(x\)\(i\) 时刻死亡,也不要忘记连逆否命题

乍一看这点数很合理,已经降到 \(4m+2n\) 了,但是还能再少:真的有必要在 \(i/i+1\) 时刻给 \(y\) 建两个点吗?

其实并不需要,站到统计答案的角度看,我们只关注在 \(T+1\) 时刻的生死,具体是什么时候死的不重要

只存每个点作为 \(x\) 时刻的生死点和 \(T+1\) 时刻的生死点,作为 \(y\) 时可以 lower_bound 下一个作为 \(x\) 的时候

最后是统计答案,不能同生的是自己生的后继中它人死,和那些自己生的后继中有自己死的点,注意去重

这明显是一个 \(DAG\) 上可达点统计问题,使用 bitset 优化可以做到 \(\Theta(\frac {nm}{\omega})\)

posted @ 2020-02-17 22:29  yspm  阅读(176)  评论(3编辑  收藏  举报