sat求解器解哈密顿回路

资料:https://ozanerdem.github.io/jekyll/update/2019/11/17/representation-in-sat.html

https://modref.github.io/papers/ModRef2019_In%20Pursuit%20of%20an%20Efficient%20SAT%20Encoding%20for%20the%20Hamiltonian%20Cycle%20Problem.pdf

https://pysathq.github.io/

from pysat.solvers import Glucose3

vertices_number=4   #顶点的数量
edges_number=3      #边的数量
str=input()
vertices_number,edges_number=str.split()
vertices_number=eval(vertices_number)
edges_number=eval(edges_number)

check_edges=[0]*(vertices_number*vertices_number+1)

#读入数据
for i in range(edges_number):
    num=input()
    num1,num2=num.split(' ')
    num1=eval(num1)
    num2=eval(num2)
    check_edges[(num1-1)*vertices_number+num2]=1
    check_edges[(num2-1)*vertices_number+num1]=1
    

g=Glucose3()    #求解器的创建

#解决重复出现的问题
for i in range(0,vertices_number):    
    g.add_clause([-(i*vertices_number+i+1)])

for i in range(vertices_number):
    for j in range(vertices_number):
        for k in range(vertices_number):
            if(j!=k):
                g.add_clause([-(i*vertices_number+j+1),-(i*vertices_number+k+1)])

for i in range(0,vertices_number):
    for j in range(0,vertices_number):
        g.add_clause([-(i*vertices_number+1+j),-(j*vertices_number+1+i)])

#为每一步强制选择至少一个边缘
for i in range(vertices_number):
    ls=list()
    for j in range(vertices_number):
        ls.append(i*vertices_number+1+j)
    g.add_clause(ls)

#强制访问每个顶点
for i in range(vertices_number):
    ls=list()
    for j in range(vertices_number):
        ls+=[j*vertices_number+1+i]
    g.add_clause(ls)
    

#强制路径由真实边缘组成
for i in range(1,vertices_number*vertices_number+1):
    if check_edges[i]!=1:
        g.add_clause([-i])

g.solve()
if g.solve==False:
    print('NO')

flag=0

while g.solve()==True:
    
    ans=[0]
    ans+=list(g.get_model())
    now=0
    the_ans=[1]
    for i in range(1,vertices_number+1):
        if(ans[i]==i):
            now=i
    the_ans+=[now]
    while(True):
        if(ans[(now-1)*vertices_number+1]==(now-1)*vertices_number+1):
            break
        for i in range(vertices_number):
            if(ans[(now-1)*vertices_number+1+i]==(now-1)*vertices_number+1+i):
                now=i+1
                the_ans+=[now]
                break
    
    ls=list()
    for i in range(1,vertices_number*vertices_number+1):
        if ans[i]==i:
            ls+=[-i]
    g.add_clause(ls)
    if len(the_ans)!=vertices_number:
        continue;
    else:
        flag=1
        for i in range(vertices_number):
            print(the_ans[i],end=' ')
        print(1)
    
if flag==0:
    print('NO')  

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值