2-SAT问题,通俗的说就是有n对点(2n个点),从每对点中选出一个点,共选出n个点,而且要满足若干个这样的条件:某两点不能同时被选出。
设一对点为x、~x,如果a被选出则b一定要被选出,就在图中加有向弧(a,b)表示这种关系。那么如果a,b(a!=b,a!=~b)不能同时被选出,那么加两条有向弧(a,~b),(b,~a)。这样由图的对称性可以证明,2-SAT有解等价于任取x、~x,x、~x不在一个强联通分量中。
现在讨论一下特殊情况的意义。建图的过程中,如果a=b时,只用加一条有向弧(a,~a);这样也是有意义的,可表示a不能出现(~a必须被选出)。如果a=~b时,会加两条有向弧(a,a),(b,b),属于重边,无意义。这两种特殊情况都满足图的对称性:(a,~b)和(b,~a)同时存在,故不影响2-SAT的正确性。这样可以泛化一下满足条件,变成拓展的2-SAT:如果条件对应的若干个有向弧保证(a,~b)和(b,~a)同时存在,那么就可以转化最原始的2-SAT问题来解决。举个例子,如果有满足条件要求a必须出现,那么只需添加其对应的有向弧(~a,a)。这样2-SAT的应用范围就被大大增强了。
///2
2-sat 算法
2-sat问题描述:
有n二元个组(xi, yi),现在有些组之间的元素是相互冲突的,如xi, 和yj相互冲突,现在要你从每个组中选出一个元素,使得他们不会相互冲突。
算法:
1. 建图。
对于有冲突的两个元素xi, yj,现在在原图中建两条这样的边<xi, xj>,<yj, yi>。
2, 求图中的强连通分量。
如果存在二元组(xi, yi)在同一个强连通分量中,则不存在答案,直接退出算法.
否则,就将每个连通分量合并成一个点,得到新图G’.
3, 我们可以知道得到的新图是一个有向无环图,对其进行拓扑排序,得到a0,a1,..,am;
现在对于拓扑序列中的元素进行着色,对于序列中没有着色的点ai,将它着色为1,然后寻找它的原图中属于这个连通分量的点的对称点(也就是二元组中的另一个点,例如xi的对称点是yi)所在的连通分量s,将其染成2,然后在新图中对这个点s进行dfs,将它能访问到的点染成2.
4, 最后同种颜色的点就是一组满足要求的解.
3
2-SAT问题:
每组有2个元素,必须取且只能取其中一个,相当与x和~x,同时有一些相斥关系,比如选了x就不能选y,记a->b表示选了a就必须选b,那么x与y相斥 <=> x->~y且y->~x <=> ~(x∧y) <=> (~x∨~y)
2-SAT问题就是求把包含2个元素的布尔式取∧后得到true的一组解
对于k-SAT,k > 2是NP问题
如果选择的次序不当,对于x可能它的后继有存在~x,于是需要回溯,算法的改进就是如何给出一个恰当的选择次序。
算法:
建图:对于x->y,连一条x到y的边,根据对称性,~y->~x,同样连一条~y到~x的边
因为关系->具有传递性,故如果存在一个强连通分量,则选取其中任意一个结点,其余的结点也同样会被选到,故可以先缩点,如果x和~x在同一个强连通分量里,则无解。
否则,得到新的有向无环图
在新图中按照拓扑反序开始选择,若当前结点没有选择,则选择当前结点并删除对称结点以及对称结点的前驱。
因为采用了拓扑反序,不存在未处理的后继
强连通分量SCC
Kosaraju算法
一次DFS搜出拓扑序,第二次按照拓扑序在反图上DFS
Tarjan算法
pre[u]表示u结点的访问时间,low[u]表示u以及u的后代能访问到的最早的最先结点v的pre[v]
如果pre[u] == low[v],则说明u是DFS树中u所在SCC的起始点,这时u之后栈内的结点都是u所在SCC中的结点,将它们出栈并染色
计算low[u]的方法和无向图求割顶割边时类似
(u, v) in E
若v未被访问,即(u, v)为树枝边,low[u] = min(low[u], low[v])
若v已被访问,如果v在栈中,(u, v)可以为后向边也可以为连接同一个DFS树中没有后代关系的两个结点的交叉边,
low[u] = min(low[u], pre[v])
如果v不在栈中,(u, v)为连接不同DFS树的交叉边,v处于另一个SCC,不必考虑
Gabow算法
和Tarjan的思想一样,不过用到了两个栈,一个栈S和原来一样,另一个栈P保存DFS树中SCC的起始点
S和P每次都把树边的结点压入栈,如果(u, v) in E 是且v在S栈中,则表示出现了环,将P中的结点出栈直到v。当结点访问u的后代后,u在P的栈顶,说明u是所在SCC的起始点,同Tarjan算法把S栈内结点出栈并染色,注意别忘了把P栈的栈顶元素出栈。
三种算法中Kosaraju最容易理解,但需要存反图并且两次DFS,但其实另两种算法也容易理解,Tarjan算法与图论中很多算法的原理相同,Gabow算法在Tarjan算法基础上不需要频繁跟新low数组。个人比较偏向于使用Tarjan算法。
PKU 3207
判断圆上的线是否可能相交,推出互斥关系,判断2-SAT问题是否有解
此题数据非常弱
PKU 3678
巧妙的建图:对于x必须选,连~x->x的边
注意不要少加边了
PKU 2723
二分+强连通判无解
PKU 3648
输出一组未被选择的解,注意新郎必须选
PKU 3683
处理一下时间
PKU 2749
二分建图后判是否有解,先排序的话速度会快一些
HIT 1917
标准的2-SAT,测试模板