对于SAT问题我们介绍如下两个解决方法:
1、DPLL回溯算法
2、WALKSAT局部搜索算法
一、DPLL算法
DPLL算法相对于枚举的模型检验方法有以下三个改进:
1、及早终止:算法可以用部分完成的模型来判断该语句是否一定为真或假。及早终止避免了搜索空间的全部子树。
2、纯符号启发式:纯符号是指在所有子句中以相同“符号位”(即都为正文字或都为负文字)出现的符号。如在、
、
中
和
为纯符号,
不是纯符号。要注意的是,在检验符号是否为纯时,算法可以忽略自模型开始构造以来已知为真的子句。例如在模型中有
,则
为真,则
为纯符号。
3、单元子句启发式:单元子句即只有一个文字的子句。在DPLL中,单元子句定义为除某个文字以外的所有其他文字都被模型赋值为的子句。例如在模型中有
,则
变为
,即单元子句。单元子句启发式在余下的部分出现分支前对所有这样的符号完成赋值。
伪代码如下:
解释:DPLL-SATISFIABLE函数用于判断SAT问题是否可满足。输入一阶逻辑语句,将其转化为CNF形式,
为CNF的子句集合,
为
中所有命题符号,算法调用DPLL。DPLL函数首先判断在当前赋值
下,是否可以及早终止,如果每个子句都满足则成功,如果存在子句为假也可以说明失败。之后算法应用两个启发式,FIND-PURE-SYMBOL找纯符号,FIND-UNIT-CLAUSE找单元子句。很明显DPLL本质上是可能模型的递归深度优先枚举算法。
一些其他的启发式技巧:
1、成分分析:DPLL为变量赋值,子句集可能变为不相交的子集,称为成分,共享未赋值变量。该启发式的优点是可以独立考虑各成分来加快速度。
2、变量和值排序:类似CSP中的度启发式,该启发式总是建议选择在剩余子句中出现最频繁的变量。对变量的赋值总是先真后假。
3、智能回溯:普通的回溯方法速度很慢,智能回溯则直接回溯到导致冲突的相关点上,从而加速求解。
4、随机重启:有时从搜索树顶端重新开始要好过照原路继续搜索。
5、智能索引:如果可以快速索引到如“变量以正文字出现的所有子句集”则可以加快算法速度。
二、WalkSAT
WALKSAT算法在每次迭代中选择一个未得到满足的子句,并从该子句中选择一个命题符号进行翻转操作(即真假值改变)。它在两种方法中以某一概率随机选择一个来挑选要翻转的符号:(1)“最小冲突”,即最小化新状态下未得到满足语句的数量;(2)“随机行走”,即随机挑选符号。策略(2)即避免陷入局部最优解。
解释:为CNF子句集合,
为选择两个方法的概率,
为设定的最大翻转次数,
随机初始化。如果当前
满足所有子句,则返回模型。否则随机选择一个未满足的
,再选择次子句中的符号进行翻转。
如果WALKSAT返回一个模型,那么输入语句确实是可满足的。如果它返回则可能有两个原因:语句是不可满足的,或者需要给算法更多的时间。