首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从SAT转换到3-SAT

从SAT转换到3-SAT
EN

Stack Overflow用户
提问于 2014-12-03 00:33:08
回答 2查看 4.3K关注 0票数 3

有没有人知道一个很好的程序,把每个子句有任意数量变量的CNF文件转换成每个子句有3个变量的CNF文件(3-CNF)?我在计算机科学书籍中见过这种算法,但在任何地方都找不到实现,如果别人已经这么做了,我也不愿意浪费时间自己实现它。谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-21 11:31:58

我也不知道有什么程序可以这样做,但是算法非常简单,所以我只编写了下面的python脚本(下载),它以DIMACS格式读取通用的CNF,并以DIMACS格式写出相当于3-SAT问题的CNF:

代码语言:javascript
复制
from __future__ import print_function
import fileinput

cnf = list()
cnf.append(list())
maxvar = 0

for line in fileinput.input():
    tokens = line.split()
    if len(tokens) == 0 or tokens[0] == "p" or tokens[0] == "c":
        continue
    for tok in tokens:
        lit = int(tok)
        maxvar = max(maxvar, abs(lit))
        if lit == 0:
            cnf.append(list())
        else:
            cnf[-1].append(lit)

assert len(cnf[-1]) == 0
cnf.pop()

new_cnf = list()
for clause in cnf:
    while len(clause) > 3:
        new_clause = list()
        for i in range(0, len(clause), 2):
            if i+1 < len(clause):
                new_cnf.append(list())
                new_cnf[-1].append(clause[i])
                new_cnf[-1].append(clause[i+1])
                maxvar += 1
                new_cnf[-1].append(-maxvar)
                new_clause.append(maxvar)
            else:
                new_clause.append(clause[i])
        clause = new_clause
    new_cnf.append(clause)

print("p cnf %d %d" % (maxvar, len(new_cnf)))
for clause in new_cnf:
    print(" ".join([ "%d" % lit for lit in clause ]) + " 0")

有趣的地方当然是for clause in cnf:循环,它将存储在cnf中的一般sat问题转化为存储在new_cnf中的3-sat实例。它通过翻译诸如

代码语言:javascript
复制
(A[1] or A[2] or A[3] or A[4] or A[5] or A[6] or A[7])

转换成以下一组从句。

代码语言:javascript
复制
(A[1] or A[2] or ~X[1])
(A[3] or A[4] or ~X[2])
(A[5] or A[6] or ~X[3])

(X[1] or X[2] or X[3] or A[7])

前三个子句添加到new_cnf中。最后一个子句不是3-sat,因此算法在最后一个子句上重新运行,产生以下新子句:

代码语言:javascript
复制
(X[1] or X[2] or ~Y[1])
(X[3] or A[7] or ~Y[2])

(Y[1] or Y[2])

这是所有的3-sat子句,所以它们被添加到new_cnf中,算法继续使用来自cnf的下一个子句。(如果最后一个子句不是3-sat,则算法将一直工作到只剩下3-sat子句为止。最后一个子句的长度在每次迭代中大约减半。)

票数 6
EN

Stack Overflow用户

发布于 2014-12-03 00:41:48

SAT在多项式时间内是不可解的(根据目前的知识)。2-SAT在多项式时间内是可解的。

因此,从一般SAT到2-SAT的转换不会很快(不是在多项式时间内),否则我们会找到一个适用于SAT的多项式时间算法。

换句话说,将SAT转换为2-SAT所需的时间与解决SAT的时间大致相同。

也许你是说3-SAT,不是2-SAT?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27261641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档