我写了一个我认为是quite interesting question的答案,但不幸的是,在我发帖之前,其作者删除了该问题。我在这里重新发布问题摘要和答案,以防其他人使用。
假设我有一个SAT求解器,给定一个联合正规形式的布尔公式,返回一个解决方案(满足公式的变量赋值)或者问题不可满足的信息。
我可以使用此解算器查找所有解决方案吗?
答案 0 :(得分:9)
当然可以。当MiniSat [1]找到解决方案时
s SATISFIABLE
v 1 2 -3 0
(解决方案1 = True
,2 = True
,3 = False
)然后你必须在原始CNF [2]中加入禁止此解决方案的条款:
-1 -2 3 0
(这意味着,1或2必须是False
或3必须是True
)。然后你再次解决。你这样做直到求解器返回UNSAT,即没有更多的问题解决方案。您将为每次迭代插入一个子句,并且每个子句将具有与解决方案相同的格式,除了它全部被反转并且在末尾有0
使用MiniSat的C ++接口来实现这一点要快得多,因为它可以保存中间数据并且迭代速度会更快。
[2] http://fairmut3x.wordpress.com/2011/07/29/cnf-conjunctive-normal-form-dimacs-format-explained/
答案 1 :(得分:8)
肯定有一种方法可以使用你描述的SAT解算器来找到SAT问题的所有解决方案,尽管它可能不是最有效的方法。
只需使用求解器找到原始问题的解决方案,添加一个除了排除刚刚找到的解决方案之外什么都不做的子句,使用求解器找到新问题的解决方案,等等。继续前进,直到遇到不可满足的问题。
例如,假设您要满足(X or Y) and (X or Z)
。有五种解决方案:
四个X
为真,Y
和Z
为任意。
一个X
为假,Y
和Z
为真。
所以你运行你的求解器,让我们说它给你解决方案(X, Y, Z) = (T, F, F)
。您可以使用约束
not (X and (not Y) and (not Z))
此约束可以重写为子句
(not X) or Y or Z
现在,您可以针对新问题运行求解器
(X or Y) and (X or Z) and ((not X) or Y or Z)
等等。
就像我说的,这是一种做你想要的方式,但它可能不是最有效的方式。当您的SAT求解器正在寻找解决方案时,它会对该问题有很多了解,但它不会将所有这些信息返回给您 - 它只是为您提供了找到的解决方案。当您再次运行解算器时,它必须重新学习丢弃的所有信息。