在实际问题中2-SAT问题在大多数时候表现成以下形式:有2N个物品,每2个分为一组,现在要选出N种物品,同组物品不能同时选取,问你在满足题目要求的情况下能不能按规则选出物品,如果可以,那么可能的方案是什么。
在本质中是这样的:对于一个合取范式,是否有一种输入使得他的输出是1,具体点就是类似这样的布尔表达式(x1 or x2 or x3)and(x3 or x4)and(not x1 or x5)对于所有的x是否有一种01取值,使得最后的结果是1。
【建模】
建立一个2N阶的有向图,其中的点分为N对,每对点表示布尔序列A的一个元素的0、1取值(以下将代表A[i]的0取值的点称为i,代表A[i]的1取值 的点称为i')。图中的边具有特定含义。若图中存在边<i, j>,则表示若选了i必须选j。
【O(NM)算法:求字典序最小的解】
(1)给每个点设置一个状态V,V=0表示未确定,V=1表示确定选取,V=2表示确定不选取。称一个点是已确定的当且仅当其V值非0。设立两个队列Q1和Q2,分别存放本次尝试选取的点的编号和尝试不选的点的编号。
(2)若图中所有的点均已确定,则找到一组解,结束,否则,将Q1、Q2清空,并任选一个未确定的点i,将i加入队列Q1,将i'加入队列Q2;
(3)找到i的所有后继。对于后继j,若j未确定,则将j加入队列Q1;若j'(这里的j'是指与j在同一对的另一个点)未确定,则将j'加入队列Q2;
(4)遍历Q2中的每个点,找到该点的所有前趋(这里需要先建一个补图),若该前趋未确定,则将其加入队列Q2;
(5)在(3)(4)步操作中,出现以下情况之一,则本次尝试失败,否则本次尝试成功:
<1>某个已被加入队列Q1的点被加入队列Q2;
<2>某个已被加入队列Q2的点被加入队列Q1;
<3>某个j的状态为2;
<4>某个i'或j'的状态为1或某个i'或j'的前趋的状态为1;
(6)若本次尝试成功,则将Q1中的所有点的状态改为1,将Q2中所有点的状态改为2,转(2),否则尝试点i',若仍失败则问题无解。
该算法的时间复杂度为O(NM)(最坏情况下要尝试所有的点,每次尝试要遍历所有的边),但是在多数情况下,远远达不到这个上界。
具
体实现时,可以用一个数组vst来表示队列Q1和Q2。设立两个标志变量i1和i2(要求对于不同的i,i1和i2均不同,这样可以避免每次尝试都要初始
化一次,节省时间),若vst[i]=i1则表示i已被加入Q1,若vst[i]=i2则表示i已被加入Q2。不过Q1和Q2仍然是要设立的,因为遍历
(BFS)的时候需要队列,为了防止重复遍历,加入Q1(或Q2)中的点的vst值必然不等于i1(或i2)。中间一旦发生矛盾,立即中止尝试,宣告失败。
如果原图中的同一组点编号都是连续的(01、23、45……)则可以依次尝试第0对、第1对……点,每对点中先尝试编号小的,若失败再尝试编号大的。这样一定能求出字典序最小的解(如果有解的话),因为一个点一旦被确定,则不可更改。
如果原图中的同一对点编号不连续(比如03、25、14……)则按照该对点中编号小的点的编号递增顺序将每对点排序,然后依次扫描排序后的每对点,先尝试其编号小的点,若成功则将这个点选上,否则尝试编号大的点,若成功则选上,否则(都失败)无解。
题目例如HDU1814
【O(M)算法】
可以将图中所有的强连通分支全部缩成一个点(因为强连通分支中的点要么都选,要么都不选),然后按照拓扑逆序(每次找出度为0的点,具体实现时,在建分支邻接图时将所有边取反)遍历分支邻接图,将这个点(表示的连通分支)选上,并将其所有对立点(注意,连通分支的对立连通分支可能有多个,若对于两个连通分支S1和S2,点i在S1中,点i'在S2中,则S1和S2对立)及这些对立点的前趋全部标记为不选,直到所有点均标记为止。这一过程中必然不会出现矛盾 ,详细证明过程省略,详细的可以看伍昱的《由对称性解2-SAT问题》和赵爽的《2-SAT解法浅析》两篇。看证明的时候注意对称性,就是说如果x,y在同一个连通分支,那 么~x,~y也在同一个连通分支,如果x到y有路,那么~y到~x也有路,注意这个对称性的特点的话,那两篇文章里的证明也就不难看懂了。。
无解判定:若求出所有强分支后,存在点i和i'处于同一个分支,则无解,否则必定有解。
时间复杂度:求强分支时间复杂度为O(M),拓扑排序的时间复杂度O(M),总时间复杂度为O(M)。
该算法的时间复杂度低,但是只能求出任意一组解,不能保证求出解的字典序最小。
【其它】
解决问题时要注意挖掘限制条件,用于建模。
例如两个数的逻辑运算:
1、A AND B=0.这要求A和B不同时为1。既然不同时为1,那么A取1时,B必须取0;B取1时,A必须取0.所以,要连得边便是A+n->B, B+n->A。
2、A AND B=1.这要求A和B同时为1。换句话说,A和B不能是0.那要怎么样体现在图中呢?我们知道,判断一个2-sat问题是否存在合法方案的方法是,缩点后判断有没有两个同组点属于同一个连通分量。我们需要A和B都必须是1,那么我们就让A和B必须选0时无解即可。也就是说,连边A->A+n, B->B+n。这样的话,假如构图完成后,A必须取0,那么由于存在边A->A+n,所以A也必须取1,那么就不可能是一个合法方案(导出矛盾)。所以,这两条边能保证,有合法方案的话,一定是A取1(选A+n节点)的情况。
3、A OR B=0.这要求A和B同时为0.方法和2类似,方向变一下而已,理由同上。
4、A XOR B=0.这要求A=B。所以,A为0时,B必须为0,同理B为0时,A必须为0.所以添加边:A->B,B->A,A+n->B+n,B+n->A+n。