DPLL本质上是一种回溯算法,这是递归调用背后的主要思想。
该算法在尝试分配时构建解决方案,您有一个部分解决方案,随着您的继续,它可能会被证明成功或不成功。该算法的天才之处在于如何构建部分解决方案。
首先,让我们定义什么是单元子句:
单元子句是一个子句,它恰好具有一个仍未分配的文字,而其他(已分配的)文字 - 都被分配为 false。
此子句的重要性在于,如果当前赋值有效 - 您可以确定未赋值文字中变量的值是什么 - 因为文字必须为真。
例如:如果我们有一个公式:
(x1 \/ x2 \/ x3) /\ (~x1 \/ ~x4 \/ x5) /\ ( ~x1 \/ x4)
我们已经分配了:
x1=true, x4=true
然后(~x1 \/ ~x4 \/ x5)
是一个单元子句,因为您必须x5=true
在当前部分赋值中进行赋值才能满足该子句。
该算法的基本思想是:
- “猜”一个变量
- 查找从上次分配创建的所有单元子句并分配所需的值
- 迭代重试第2步,直到没有变化(找到传递闭包)
- 如果当前赋值不能为所有子句产生 true - 从递归折叠并重试不同的赋值
- 如果可以 - “猜测”另一个变量(递归调用并返回 1)
终止:
- 无处可去“回到”并改变“猜测”(无解)
- 所有子句都满足(有解决方案,算法找到了)
您还可以查看这些讲座幻灯片以获取更多信息和示例。
使用示例和重要性:
DPLL 尽管已有 50 年历史,但仍然是大多数 SAT 求解器的基础。
SAT 求解器对于解决难题非常有用,例如软件验证中的一个示例 - 您将模型表示为一组公式,以及您想要验证的条件 - 并在其上调用 SAT 求解器。虽然指数最坏情况 - 平均情况足够快并且在行业中广泛使用(主要用于验证硬件组件)