如何通过SAT和优化解决顶点覆盖问题?

时间:2019-11-29 14:18:30

标签: c++ algorithm optimization sat

所以现在我正在使用SAT解决最小顶点覆盖问题,这是我对图形G的编码= {V,E}具有k个顶点覆盖,这是这些子句:

Let n = sizeof(V);

首先,在顶点覆盖层中至少有一个顶点:

For i in {1..k}
    Add clause (x<1,i> ∨ x<2,i> ∨ ··· ∨ x<n,i>);

然后,没有一个顶点可以在顶点覆盖中出现两次:

For j in {1..n}
    For l and m in {1..k} with l < m
        Add clause (¬x<j,l> ∨ ¬x<j,m>) 

此后,顶点覆盖中的特定位置只能出现一个顶点:

For j in {1..k}
    For l and m in {1..n} with l < m
        Add clause (¬x<l,j> ∨ ¬x<m,j>) 

最后,顶点覆盖中的至少一个顶点应该来自边缘:

For i and j in each edge e from E
    Add clause (x<i,1> ∨ x<i,2> ∨ ... ∨ x<i,k> ∨ x<j,1> ∨ ... ∨ x<j,k>)

现在,我可以通过使用这种编码来获得最小的顶点覆盖,但是效率很差。对于只有<20个顶点的任何图形,我都只能得到结果,否则要花几分钟和几个小时才能得到结果。我现在正在考虑将其从SAT进一步减少到3SAT。但是看起来我不能简单地将所有子句从nCNF更改为3CNF以获得相同的结果。谁能帮我弄清楚下一步该怎么做?我需要全新的编码吗?

非常感谢您。

顺便说一句,我正在使用MiniSAT作为求解器。

1 个答案:

答案 0 :(得分:1)

首先,让我假设在理解您的编码时遇到一些麻烦,因此我将从头开始。这就是我要解决这个问题的方式。

注意:我的示例基于SMT-LIB语法,可以使用 MaxSMT 求解器进行求解,例如z3和{ {3}}。但是,由于它不使用任何SMT功能,因此您实际上可以使用 MaxSAT 比赛中使用的optimathsat编写相同的内容。在选择求解器来解决问题时,这将为您提供更多选择。我可能是错的,但是我推测 MaxSAT 求解器在此特定问题上的性能可能会优于 MaxSMT


让G = {V,E}为图。

首先,为图形中的每个顶点声明一个布尔变量:

(declare-fun vertex_1 () Bool)
...
(declare-fun vertex_K () Bool)

(任何没有边的顶点都应该省略,因为那样会浪费时间。)

第二,为图中连接顶点i和顶点j的每个边声明一个布尔变量(假定无向)

(declare-fun edge_i_j () Bool)
...

第三,断言必须edge_i_j覆盖每个边缘:

(assert edge_i_j)
...

第四,如果覆盖了边缘edge_i_j,则顶点i或顶点j必须为true

(assert (=> edge_i_j (or vertex_i vertex_j)))
...

第五,对于每个带有 soft子句的断言,vertex_i应该为vertex_i。如果不是这种情况,请对false的值收取价值1的罚款:

cover

最后,解决问题:

(assert-soft (not vertex_i) :weight 1 :id cover)

在这一点上,可以使用任何高效的 MaxSAT / MaxSMT 引擎(例如the standard WCNF format)来获得一个模型,该模型可以覆盖使用时的所有边缘最少数量的顶点(如果有)。