图论专题-学习笔记:2 - SAT 问题

图论专题-学习笔记:2 - SAT 问题

一些 update

update 2021/11/12:修正了文章中的一些语言。

1. 前言

本篇文章将会对 2 - SAT 问题做一个讲解。

前置知识:强连通分量/缩点(我的博客链接/强连通分量 - OI Wiki)。

2. 详解

首先我们需要知道 2 - SAT 是什么。

实际上 2 - SAT 是 k - SAT 的一种特殊情况。

k - SAT 问题的一般描述就是有一些物品,每个物品均有 k k k 个状态,给出一些限制条件,诸如 A 为 a 状态则 B 为 b 状态之类的,问有无可行解,有时还会让你求解。

目前 k - SAT 问题( k > 2 k > 2 k>2)已经被证明无多项式解法,只能暴力求解,但是 2 - SAT 因为其优良的性质使得当我们只需要任意一组解或者是判有无解的时候,可以采用 O ( n + m ) O(n + m) O(n+m) 算法解决。

2 - SAT 一般描述如下:

现给出 n n n 个布尔类型的值,可真可假,有 m m m 种限制条件,限制条件是如下 3 种情况之一:

  • A = p A = p A=p,则 B = q B = q B=q
  • A = p A = p A=p B = q B = q B=q 至少有一个成立。
  • A 必须为 p p p

剩余别的所有情况都可以转化为上述三种情况。

现给出这些限制条件,问你有没有一组取值,使得这组取值能够满足所有限制条件,如果有还需要求出一组可行解。

解决 2 - SAT 问题的方案一般是建图。

对于每一个变量 x x x 我们建两个点 x 0 , x 1 x_0,x_1 x0,x1,分别表示变量 x x x 取 0 或者取 1。

  • A = p A = p A=p,则 B = q B = q B=q

为了方便,只讨论若 A = 1 A = 1 A=1,则 B = 1 B = 1 B=1,其余情况可以类推。

考虑连边 A 1 → B 1 , B 0 → A 0 A_1 \to B_1,B_0 \to A_0 A1B1,B0A0,这么连边的意义是如果 A = 1 A = 1 A=1,那么根据连边可以推出 B = 1 B = 1 B=1,如果 B = 0 B = 0 B=0,那么根据连边可以推出 A = 0 A = 0 A=0

注意 B 0 → A 0 B_0 \to A_0 B0A0 正确性是因为原命题的逆否命题正确。

在这里插入图片描述

  • A = p A = p A=p B = q B = q B=q 至少有一个成立。

为了方便,只讨论 A = 1 A = 1 A=1 B = 1 B = 1 B=1 至少有一个成立,其余情况可以类推。

考虑连边 A 0 → B 1 , B 0 → A 1 A_0 \to B_1,B_0 \to A_1 A0B1,B0A1,意义是如果 A = 0 A = 0 A=0 B = 1 B = 1 B=1 必然成立,同理 B = 0 B = 0 B=0 A = 1 A = 1 A=1 必然成立。

在这里插入图片描述

  • A 必须为 p p p

为了方便,只讨论 A = 1 A = 1 A=1 的情况,其余情况可以类推。

对于这种情况,直接连边 A 0 → A 1 A_0 \to A_1 A0A1,意义是如果 A = 0 A = 0 A=0,根据连边可以发现 A = 1 A = 1 A=1,这意味着 A ≠ 0 A \ne 0 A=0,只能是 A = 1 A = 1 A=1,该连边可以控制 A ≠ 0 A \ne 0 A=0

在这里插入图片描述

这么操作之后,我们得到了一张有向图,其中的有向边表示推出关系。

那么接下来如何判断有无解呢?

采用强连通分量算法。

假设说某变量 x x x,其两个点 x 0 , x 1 x_0,x_1 x0,x1 处于同一个强连通分量中,这说明从 x = 0 x = 0 x=0 出发能够推出 x = 1 x = 1 x=1,从 x = 1 x = 1 x=1 出发能够推出 x = 0 x = 0 x=0,因此 x ≠ 0 , x ≠ 1 x \ne 0,x \ne 1 x=0,x=1,这样就无解了。

那么如何求出一组可行解呢?

首先对这一张图缩点,然后我们就得到了一张 DAG。

如果 x 0 x_0 x0 处于强连通分量 A A A 中, x 1 x_1 x1 处于强连通分量 B B B 中,且 A A A 的拓扑序小于 B B B,那么有两种可能:

  • x 0 , x 1 x_0,x_1 x0,x1 互不干扰。
  • x 0 x_0 x0 能够推出 x 1 x_1 x1

发现无论哪种情况选择 x 1 x_1 x1 都是正确的,因此对于变量 x x x 而言, x 0 , x 1 x_0,x_1 x0,x1 哪个拓扑序大选哪个能够保证选出来的解是正确的。

所以我们需要对建出来的图缩点,然后跑拓扑排序,求出拓扑序,然后求解……

吗?

不需要!在求强连通分量的时候我们已经得到拓扑序了。

若采用 Kosaraju 算法(两遍 dfs):

求强连通分量的时候我们会得到一个 Color[] 数组表示其属于的强连通分量的编号,而根据 Color[] 数组可以直接推出两个强连通分量的拓扑序大小:

  • 对于缩点之后的图上的两个点 i , j i,j i,j,如果 C o l o r i < C o l o r j Color_i < Color_j Colori<Colorj,则 i i i 一定能够走到 j j j。换言之,求出这张图的拓扑序后 i i i j j j 前面。

上述结论的证明过程我在我的文章图论专题-学习笔记:强连通分量中证明过,此处不再证明,想了解的读者可以进入我的文章了解。

实质上 Color[] 就是新图的拓扑序(之一)。

若采用 Tarjan 算法:

采用 Tarjan 算法需要注意的一点就是求出的 scc[] 数组是反过来的,也就是说 scc[] 越大其拓扑序越小,这点跟 Kosaraju 算法是不一样的,也比较容易出错。

证明的话实际上是因为 Tarjan 求强连通分量的时候我们是倒着标记强连通分量的,因此拓扑序最小的强连通分量其标号是最大的。

我更推荐 Kosaraju 算法~

洛谷模板题:P4782 【模板】2-SAT 问题

洛谷的模板题只有情况 2。

Code:GitHub CodeBase-of-Plozia P4782 【模板】2-SAT 问题.cpp

3. 总结

2 - SAT 问题的一般解法是根据逻辑关系进行拆点连边,然后求强连通分量判断有无解以及求出一组解。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值