我对理解DPLL算法有一些问题,我想知道是否有人能向我解释一下,因为我觉得我的理解是不正确的。
我理解的方式是,我取一些文字的集合,如果每个子句都为真,那么模型为真;但如果某个子句为假,那么模型为假。
我递归地检查模型,寻找单元子句。如果存在单元子句,我就将该单元子句的值设置为真,然后更新模型。移除所有现在为真的子句,并移除所有现在为假的文字。
当没有剩余单元子句时,我选择任何其他文字,并为其赋值使其为真和为假,然后再次移除所有现在为真的子句,并移除所有现在为假的文字。
回答:
DPLL要求问题以析取范式(CNF)表示,即作为一组子句,每个子句都必须被满足。
每个子句都是一组文字{l1, l2, ..., ln}
,表示这些文字的析取(即,至少一个文字必须为真才能满足该子句)。
每个文字l
断言某个变量为真(x
)或为假(~x
)。
如果子句中任何一个文字为真,则该子句被满足。
如果子句中所有文字都为假,则该子句是不可满足的,因此该问题也是不可满足的。
一个解决方案是将真/假值分配给变量,使得每个子句都得到满足。DPLL算法是对这种解决方案的一种优化搜索。
DPLL本质上是一种深度优先搜索,它在三种策略之间交替。在搜索的任何阶段,都有一个部分赋值(即,将值分配给变量的某个子集)和一组未决子句(即,尚未满足的子句)。
(1)第一个策略是纯文字消除:如果一个未赋值的变量x
只以其正形式出现在未决子句集合中(即,文字~x
没有出现在任何地方),那么我们可以简单地将x = true
添加到我们的赋值中,并满足所有包含文字x
的子句(类似地,如果x
只以其负形式~x
出现,我们可以简单地将x = false
添加到我们的赋值中)。
(2)第二个策略是单元传播:如果一个未决子句中除了一个文字之外的所有文字都为假,那么剩下的一个文字必须为真。如果剩下的文字是x
,我们将x = true
添加到我们的赋值中;如果剩下的文字是~x
,我们将x = false
添加到我们的赋值中。此赋值可能导致进一步的单元传播机会。
(3)第三个策略是简单地选择一个未赋值的变量x
并分支搜索:一边尝试x = true
,另一边尝试x = false
。
如果在任何时候我们最终得到一个不可满足的子句,那么我们就到达了一个死胡同,必须回溯。
还有各种各样更巧妙的优化方法,但这是几乎所有SAT求解器的核心。
希望这有帮助。