前言
SAT 问题简介
SAT是可满足性、适定性(Satisfiability)问题的简称。一般形式为k-适定性问题或k-可满足性问题,简称 k-SAT。
何为布尔可满足性问题?给定一条真值表达式,包含逻辑变量、逻辑与、逻辑或以及非运算符,如:
( a ∧ ¬ b ∧ ( ¬ ( c ∨ d ∨ ¬ a ) ∨ ( b ∧ ¬ d ) ) ) ∨ ( ¬ ( ¬ ( ¬ b ∨ a ) ∧ c ) ∧ d ) (a\wedge\neg b\wedge(\neg(c\vee d\vee\neg a)\vee(b\wedge\neg d)))\vee(\neg(\neg(\neg b\vee a)\wedge c)\wedge d) (a∧¬b∧(¬(c∨d∨¬a)∨(b∧¬d)))∨(¬(¬(¬b∨a)∧c)∧d)
是否存在一组对这些变量的赋值,使得整条式子最终的运算结果为 t r u e true true?若可以,那么这个性质被称为这条逻辑公式的可满足性(satisfiability),如何快速高效地判断任意指定逻辑公式的可满足性是理论计算机科学中的一个重要的问题,也是第一个被证明为NP-完全(NP-complete,NPC)的问题。
当 k > 2 k>2 k>2时,可满足性问题是NPC问题,因此我们一般只研究 k = 2 k=2 k=2的情况。
2-SAT算法
通常所说的2-SAT问题往往需要我们处理对于 n n n个布尔变量 { x n } ( x i ∈ { 0 , 1 } ) \{x_n\}\left(x_i\in\{0,1\}\right) {xn}(xi∈{0,1})的 m m m个限制。
其每个限制都形如一个 ∨ \vee ∨运算符连接的两个简单限制条件,简单限制条件为 x i = t r u e x_i=true xi=true(记作 x i x_i xi)或 x i = f a l s e x_i=false xi=false(记作 ¬ x i \neg x_i ¬xi),因此限制条件一共有四种:
- s k = x i ∨ x j s_k=x_i\vee x_j sk=xi∨xj
- s k = ¬ x i ∨ x j s_k=\neg x_i\vee x_j sk=¬xi∨xj
- s k = x i ∨ ¬ x j s_k=x_i\vee\neg x_j sk=xi∨¬xj
- s k = ¬ x i ∨ ¬ x j s_k=\neg x_i\vee \neg x_j sk=¬xi∨¬xj
我们需要满足: ⋀ m i = 1 s i = t r u e \underset{i=1}{\overset m{ \bigwedge }}s_i=true i=1⋀msi=true
也就是需要每一个 s k s_k sk都为真。
其处理方法为:
首先建图,对变量 x i x_i xi建立两个点 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1表示选 x i = 0 x_i=0 xi=0或 x i = 1 x_i=1 xi=1,然后在新图上对每个限制按照如下方式连边。
例如对于限制 s k s_k sk,我们讨论这条限制下 a , b ∈ { 0 , 1 } a,b\in\{0,1\} a,b∈{0,1}, x i = a x_i=a xi=a时是否一定有 x j = b x_j=b xj=b,如果一定有,就连有向边 x i , a → x j , b x_{i,a}\rightarrow x_{j,b} xi,a→xj,b。
同理我们讨论 x j = a x_j=a xj=a是否一定有 x i = b x_i=b xi=b,如果一定有,就连有向边 x j , a → x i , b x_{j,a}\rightarrow x_{i,b} xj,a→xi,b
感性理解这张图,如果 x i , a x_{i,a} xi,a可达 x j , b x_{j,b} xj,b,则说明 x i = a x_i=a xi=a可以推出 x j = b x_j=b xj=b,或者说 x i = a x_i=a xi=a蕴含了 x j = b x_j=b xj=b。
因此我们知道这个可满足性问题无解的充要条件为,存在 i i i使得 x i , 0 x_{i,0} xi,0和 x i , 1 x_{i,1} xi,1处于同一个强连通分量内,这意味着 x i = 0 x_i=0 xi=0推出 x i = 1 x_i=1 xi=1,同时 x i = 1 x_i=1 xi=1推出 x i = 0 x_i=0 xi=0,因此无解。
因此我们可以使用Tarjan算法求强连通分量来判断2-SAT问题是否有解,事实上我们还可以输出一组可行解。
具体方法如下,首先对我们建图的图求强连通分量缩点,得到一张DAG,然后对DAG进行拓扑排序,则 x i x_i xi对应的两个节点中,对应的强连通分量拓扑序较为靠后的节点对应的权值,是 x i x_i xi取得的权值。
其原理是,如果 x i = a x_i=a xi=a会推出 x i = b x_i=b xi=b,那么就不能选 x i = a x_i=a xi=a,此时只能选 x i = b x_i=b xi=b。
这样我们就用Tarjan算法取得了可满足性问题的 O ( n + m ) O(n+m) O(n+m)做法。
具体的连边方式
首先,所有限制都可以转化为 x i = a ⇒ x j = b x_i=a\Rightarrow x_j=b xi=a⇒xj=b的形式进行连边,这里记录一些经典的连边方式,这样就不需要每次做转化了。
- x i = a ⇒ x j = b x_i=a\Rightarrow x_j=b xi=a⇒xj=b
- x i , a → x j , b x_{i,a}\rightarrow x_{j,b} xi,a→xj,b
- x j , ¬ b → x i , ¬ a x_{j,\neg b}\rightarrow x_{i,\neg a} xj,¬b→xi,¬a
- a ∨ b a\vee b a∨b
- a 0 → b 1 a_0\rightarrow b_1 a0→b1
- b 0 → a 1 b_0\rightarrow a_1 b0→a1
- ¬ a ∨ b \neg a\vee b ¬a∨b
- a 1 → b 1 a_1\rightarrow b_1 a1→b1
- b 0 → a 0 b_0\rightarrow a_0 b0→a0
- ¬ a ∨ ¬ b \neg a\vee\neg b ¬a∨¬b
- a 1 → b 0 a_1\rightarrow b_0 a1→b0
- b 1 → a 0 b_1\rightarrow a_0 b1→a0
- a = t r u e a=true a=true
- 转化为 a = 0 ⇒ a = 1 a=0\Rightarrow a=1 a=0⇒a=1
- a 0 → a 1 a_0\rightarrow a_1 a0→a1
- a = f a l s e a=false a=false
- 转化为 a = 1 ⇒ a = 0 a=1\Rightarrow a=0 a=1⇒a=0
- a 1 → a 0 a_1\rightarrow a_0 a1→a0
- a = b a=b a=b
- 转化为 a = 1 ⇒ b = 1 a=1\Rightarrow b=1 a=1⇒b=1,且 a = 0 ⇒ b = 0 a=0\Rightarrow b=0 a=0⇒b=0
- a ≠ b a\not=b a=b( a ⊗ b a\otimes b a⊗b)
- 转化为 a = 0 ⇒ b = 1 a=0\Rightarrow b=1 a=0⇒b=1,且 a = 1 ⇒ b = 0 a=1\Rightarrow b=0 a=1⇒b=0
- x 1 , x 2 , x 3 , . . . x_1,x_2,x_3,... x1,x2,x3,...至多一个为真
- 转化为:
- x 1 = 1 ⇒ x 2 = 0 x_1=1\Rightarrow x_2=0 x1=1⇒x2=0,且 x 1 = 1 ⇒ x 3 = 0 x_1=1\Rightarrow x_3=0 x1=1⇒x3=0,…
- 且 x 2 = 1 ⇒ x 1 = 0 x_2=1\Rightarrow x_1=0 x2=1⇒x1=0,且 x 2 = 1 ⇒ x 3 = 0 x_2=1\Rightarrow x_3=0 x2=1⇒x3=0,…
- 且 x 3 = 1 ⇒ x 1 = 0 x_3=1\Rightarrow x_1=0 x3=1⇒x1=0,且 x 3 = 1 ⇒ x 2 = 0 x_3=1\Rightarrow x_2=0 x3=1⇒x2=0,…
- …
- 注意这样连出来的边数是 O ( m 2 ) O(m^2) O(m2)级别的
- 转化为:
- x 1 , x 2 , x 3 , . . . x_1,x_2,x_3,... x1,x2,x3,...至多 k > 1 k>1 k>1个为真
- 2-sat一般不能做
- x 1 , x 2 , x 3 , . . . x_1,x_2,x_3,... x1,x2,x3,...至少 k ≥ 1 k\geq 1 k≥1个为真
- 2-sat一般不能做
- x 1 , x 2 , x 3 , . . . x_1,x_2,x_3,... x1,x2,x3,...恰好 k ≥ 1 k\geq 1 k≥1个为真
- 2-sat一般不能做
其中一些限制条件也可以在连边的时候判掉。
2-SAT原理
我们现在有 n n n个布尔变量,称为 { x n } ( x i ∈ { 0 , 1 } ) \{x_n\}\left(x_i\in \{0,1\}\right) {xn}(xi∈{0,1}),现在给出 m m m条限制,每一条限制都形如:
当 x i = a x_i=a xi=a时,有 x j = b x_j=b xj=b( a , b ∈ { 0 , 1 } a,b\in\{0,1\} a,b∈{0,1})
即: x i = a ⇒ x j = b x_i=a\Rightarrow x_j=b xi=a⇒xj=b
接下来说一下如何求解这个问题。
图的建立
点的意义
我们使用图论方法对这个问题进行求解,按照经典套路,我们需要在图上定义一个集合,然后把原问题的意义在集合内体现出来。
具体来说,我们有一个集合 S S S,同时在图上有 2 n 2n 2n个点,其中每个比尔变量 x i x_i xi对应两个点,一个叫做 x i , 0 x_{i,0} xi,0,另一个叫做 x i , 1 x_{i,1} xi,1。
我们规定 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1当中只能恰好有一个属于集合 S S S,如果 x i , 0 ∈ S x_{i,0}\in S xi,0∈S,则 x i = 0 x_i=0 xi=0;如果 x i , 1 ∈ S x_{i,1}\in S xi,1∈S,则 x i = 1 x_i=1 xi=1。
我们知道根据限制能够推出一些关系,例如如果 x i , a ∈ S x_{i,a}\in S xi,a∈S,那么一定有 x j , b ∈ S x_{j,b}\in S xj,b∈S,我们希望用边表示这一种关系,因此我们规定对于任意元素 u ∈ S u\in S u∈S, u u u在图上可达的所有点 v v v均属于 S S S。
边的意义
刚才已经定义了图中的点,以及集合 S S S。现在具体说一下图中的边是如何连接的:
对于限制: x i = a ⇒ x j = b x_i=a\Rightarrow x_j=b xi=a⇒xj=b
我们考虑一个一个向着集合 S S S内添加元素的过程,我们必然是找到一个点 u u u加入集合,然后将 u u u的所有后继加入 S S S,然后把这些后继的所有后继加入 S S S…
由于我们知道 x i = a x_i=a xi=a时, x j = b x_j=b xj=b,因此对于这个限制,我们在图上连边 x i , a → x j , b x_{i,a}\rightarrow x_{j,b} xi,a→xj,b,这样就似乎可以表示这个限制了。
(注意连边方式到这里还不完全正确)
此时我们会得到一个暴力算法:
- 枚举一个未被确定的变量 x i x_i xi
- 先选择 x i , 0 x_{i,0} xi,0,然后检查 x i , 0 x_{i,0} xi,0可达的所有点,我们将会选中他们。
- 如果发生冲突(即存在 x j , 0 , x j , 1 ∈ S x_{j,0},x_{j,1}\in S xj,0,xj,1∈S),那么就说明 x i ≠ 0 x_i\not=0 xi=0,回溯。
- 如果 x i , 0 x_{i,0} xi,0不能选,那么就选择 x i , 1 x_{i,1} xi,1,然后检查 x i , 1 x_{i,1} xi,1的可达点,检查是否有冲突,如果没有就选上它们,否则就说明无解。
但是我们会发现这个算法是会错的,举例来说,对于以下两个限制:
- y = 0 ⇒ x = 1 y=0\Rightarrow x=1 y=0⇒x=1
- y = 1 ⇒ x = 1 y=1\Rightarrow x=1 y=1⇒x=1
我们会连出这张图:
但是如果我们一开始选择 x 0 x_0 x0,后来就会发现无论选择 y 0 y_0 y0还是 y 1 y_1 y1都会有矛盾,此时就输出无解,显然是不对的。
这样会出错是因为,对于这样的一条限制 y = 0 ⇒ x = 1 y=0\Rightarrow x=1 y=0⇒x=1来说,选择 x x x的值是会对 y y y的值产生影响的,具体来说,如果 x = 0 x=0 x=0,这就说明 y ≠ 0 y\not=0 y=0,即 y = 1 y=1 y=1。
换句话说,命题 y = 0 ⇒ x = 1 y=0\Rightarrow x=1 y=0⇒x=1的逆否命题 x ≠ 1 ⇒ y ≠ 0 x\not=1\Rightarrow y\not =0 x=1⇒y=0,即 x = 0 ⇒ y = 1 x=0\Rightarrow y=1 x=0⇒y=1,具有和原命题一致的真假性,因此选择 x x x的值可能会对 y y y造成影响,因此我们需要进一步讨论 x = a ⇒ y = b x=a\Rightarrow y=b x=a⇒y=b说明了 x , y x,y x,y之间的那些关系:
- 当我们选择了 x a x_a xa时,必然有 y b y_b yb
- 当我们选择了 x ¬ a x_{\neg a} x¬a时,这条限制不提供任何约束,即有可能选择 y b y_b yb或 y ¬ b y_{\neg b} y¬b
- 当我们选择了 y b y_b yb时,这条限制不提供任何约束,即有可能选择 x a x_a xa或 x ¬ a x_{\neg a} x¬a
- 当我们选择了 y ¬ b y_{\neg b} y¬b时,必然有 x ¬ a x_{\neg a} x¬a
因此事实上对于限制 x i = a ⇒ x j = b x_i=a\Rightarrow x_{j}=b xi=a⇒xj=b来说,我们应该连接两条边:
- x i , a → x j , b x_{i,a}\rightarrow x_{j,b} xi,a→xj,b
- x j , ¬ b → x i , ¬ a x_{j,\neg b}\rightarrow x_{i,\neg a} xj,¬b→xi,¬a
此时我们再进行刚才的暴力算法,我们就获得了时间复杂度为 O ( n ⋅ m ) O(n\cdot m) O(n⋅m)的2-sat问题的dfs做法。值得一提的是,这种做法还能同时让我们获得2-sat问题字典序最小的解。
接下来简要对暴力做法的正确性进行说明:
首先我们证明解的充分性,即我们求出的解确实是原问题的一组解:
首先我们知道,对于一个限制 x i = a ⇒ x j = b x_{i}=a\Rightarrow x_{j}=b xi=a⇒xj=b,这个限制被违反当且仅当 x i , a , x j , ¬ b ∈ S x_{i,a},x_{j,\neg b}\in S xi,a,xj,¬b∈S。
如果说在算法过程中 x i , a x_{i,a} xi,a比 x j , ¬ b x_{j,\neg b} xj,¬b先选的话,发生这种情况一定不可能,因为我们选择 x i , a x_{i,a} xi,a时根据连边,一定选择了 x j , b x_{j,b} xj,b,因此后来无法选择 x j , ¬ b x_{j,\neg b} xj,¬b了,矛盾。
如果 x i , a x_{i,a} xi,a比 x j , ¬ b x_{j,\neg b} xj,¬b后选的话,这种情况还是不可能,因为根据连边的方式,如果我们选择了 x j , ¬ b x_{j,\neg b} xj,¬b,我们一定选择了 x i , ¬ a x_{i,\neg a} xi,¬a,不可能再选择 x i , a x_{i,a} xi,a,因此仍然矛盾。
因此我们就证明,我们构造出的一组解满足所有限制条件,因此是一组合法解。
接下来我们证明解的必要性,即有解的时候,我们一定能够构造出一组解。
只需证明逆否命题,即如果我们构造不出一组解,此时这个问题无解。
我们考虑求解过程在决定变量 x i x_i xi的取值时报告了无解。
此时必然是因为发生了矛盾,首先讨论选取 x i , 0 x_{i,0} xi,0时候的情况,矛盾即存在元素 x j , 0 , x j , 1 ∈ S x_{j,0},x_{j,1}\in S xj,0,xj,1∈S。
此时有两种情况,第一种情况是 x j , 0 , x j , 1 x_{j,0},x_{j,1} xj,0,xj,1都是在 x i , 0 x_{i,0} xi,0加入集合 S S S后加入集合的,此时显然选择 x i , 0 x_{i,0} xi,0会同时推出 x j = 0 x_j=0 xj=0和 x j = 1 x_j=1 xj=1,因此 x i ≠ 0 x_i\not=0 xi=0。
第二种情况是, x j , a x_{j,a} xj,a是在 x i , 0 x_{i,0} xi,0加入集合 S S S前加入集合的,而 x j , ¬ a x_{j,\neg a} xj,¬a是因为加入 x i , 0 x_{i,0} xi,0而加入集合 S S S的(换句话说存在路径使得 x i , 0 ⇝ x j , ¬ a x_{i,0}\rightsquigarrow x_{j,\neg a} xi,0⇝xj,¬a),这种情况不存在,这是因为,如果存在路径使得 x i , 0 ⇝ x j , ¬ a x_{i,0}\rightsquigarrow x_{j,\neg a} xi,0⇝xj,¬a,由于接下来说到的性质2,我们必然知道存在一条路径使得 x j , a ⇝ x i , 1 x_{j,a}\rightsquigarrow x_{i,1} xj,a⇝xi,1,因此当 x j , a ∈ S x_{j,a}\in S xj,a∈S后, x i , 1 ∈ S x_{i,1}\in S xi,1∈S,这与 x i x_i xi取值未确定矛盾,因此第二种情况不存在。
不可能存在一种情况使得 x j , 0 , x j , 1 x_{j,0},x_{j,1} xj,0,xj,1在加入 x i , 0 x_{i,0} xi,0前都在集合 S S S内,因为这违反 S S S的定义。
同理我们知道,如果在选择 x i , 1 x_{i,1} xi,1的时候发生矛盾,只可能是因为 x i ≠ 1 x_i\not=1 xi=1。此时我们就得知了 x i ≠ 0 x_i\not=0 xi=0且 x i ≠ 1 x_i\not=1 xi=1,因此得到这个可满足性问题无解。
QED.
线性算法
接下来我们说一下这个问题的线性算法,线性算法是这样的:
- 对建出来的图缩强连通分量
- 这样会得到一张DAG
- 如果存在点 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1在一个强连通分量内,则说明无解。
- 否则有解,对DAG拓扑排序, x i x_i xi的取值是它对应的两个点 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1对应的强连通分量中拓扑序较靠后的那个点的取值。
证明
接下来我们证明一下线性算法的正确性。
性质1
边的对称性:
对于任意一条有向边, ( x i , a , x j , b ) (x_{i,a},x_{j,b}) (xi,a,xj,b),都存在有向边 ( x j , ¬ b , x i , ¬ a ) (x_{j,\neg b},x_{i,\neg a}) (xj,¬b,xi,¬a),我们称为其对称边。
证明:
回忆建图的方式,这条性质是显然成立的。
性质2
路径的对称性:
对于任意一条从 x i , a x_{i,a} xi,a到 x j , b x_{j,b} xj,b的路径,必然存在对应的一条路径从 x j , ¬ b x_{j,\neg b} xj,¬b到 x i , ¬ a x_{i,\neg a} xi,¬a。
证明:
我们找到从 x i , a x_{i,a} xi,a到 x j , b x_{j,b} xj,b的路径上的每一条边的对称边,显然它们拼成一条从 x j ¬ b x_{j\neg b} xj¬b到 x i , ¬ a x_{i,\neg a} xi,¬a的路径。
算法1
我们可以据此提出一个求解2-sat问题的算法:
- 对建出来的图缩强连通分量
- 这样会得到一张DAG
- 如果存在点 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1在一个强连通分量内,则说明无解。
- 否则有解,我们通过如下过程构造解:
- 找到一个没有确定的 x i x_i xi
- 由于 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1不强连通,因此不可能存在二者相互可达。
- 如果有 x i , 0 ⇝ x i , 1 x_{i,0}\rightsquigarrow x_{i,1} xi,0⇝xi,1,那就令 x i , 1 ∈ S x_{i,1}\in S xi,1∈S。否则说明一定有 x i , 1 ⇝ x i , 0 x_{i,1}\rightsquigarrow x_{i,0} xi,1⇝xi,0,或者 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1互相不可达,此时令 x i , 0 ∈ S x_{i,0}\in S xi,0∈S。
- 如果此时我们有 x i , a ∈ S x_{i,a}\in S xi,a∈S,那就说明有 x i , ¬ a ∉ S x_{i,\neg a}\notin S xi,¬a∈/S。同时说明 x i , a x_{i,a} xi,a的所有后继都属于 S S S,把它们加入 S S S。
- 同时说明 x i , ¬ a x_{i,\neg a} xi,¬a的所有前驱都不属于 S S S。
- 直到所有的变量取值都确定,此时我们得到了一组可行解。
定理1
缩点后得到的DAG,满足没有任何一个 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1强连通,是原问题有解的必要条件。
证明其逆否命题:
如果存在 x i , 0 , x i , 1 x_{i,0},x_{i,1} xi,0,xi,1强连通,那么我们沿着 x i , 0 ⇝ x i , 1 ⇝ x i , 0 x_{i,0}\rightsquigarrow x_{i,1}\rightsquigarrow x_{i,0} xi,0⇝xi,1⇝xi,0的回路走,上面的边对应的限制条件就说明,当 x i = 0 x_{i}=0 xi=0时 x i = 1 x_i=1 xi=1,并且当 x i = 1 x_i=1 xi=1时 x i = 0 x_i=0 xi=0,此时显然无解。
QED.
定理2
按照上述算法1流程构造出的解,是原问题的一组解。
证明:
如果这组解不是原问题的一组解,那么一定存在至少一个限制被违背了,设这个限制是 x i = a ⇒ x j = b x_i=a\Rightarrow x_j=b xi=a⇒xj=b,这个限制被违反必须有 x i = a x_i=a xi=a且 x j = ¬ b x_j=\neg b xj=¬b。
假如说 x i , a x_{i,a} xi,a比 x j , ¬ b x_{j,\neg b} xj,¬b后晚加入集合,当我们加入 x j , ¬ b x_{j,\neg b} xj,¬b时,由于这条限制对应连出的边, x i , ¬ a x_{i,\neg a} xi,¬a一定也会被加入集合,因此 x i , a x_{i,a} xi,a不可能加入集合,矛盾。
否则说明 x i , a x_{i,a} xi,a比 x j , ¬ b x_{j,\neg b} xj,¬b先加入集合,但是这也不可能,因为当我们加入 x i , a x_{i,a} xi,a时,由于这条限制对应连出的边, x j , b x_{j,b} xj,b也一定加入集合,因此 x j , b x_{j,b} xj,b不可能加入集合,矛盾。
QED.
定理3
根据定理1,定理2,我们证明了:
算法1能够求出一组解,是原问题有解的充要条件。它求出的解,是原问题的一组解。
定理4
容易发现Tarjan算法+拓扑排序求解2-sat问题的过程事实上在模拟算法1,因此其的正确性也有保证。
后记
于是皆大欢喜。