DPLL算法实现n皇后问题求解

DPLL解决N皇后问题

算法综述

N皇后问题的基本要求是:同一条直线上,不允许出现一个以上的皇后.
显而易见,棋盘上不同的位置之间存在着约束的关系.
假使:皇后落在某一个棋盘上某一个位置将该位置置为True,当某一个位置上没有皇后的时候,将该位置置为False.
以二皇后为例
其对应的合取范式为:
( A ∨ B ) ∧ ( ¬ A ∨ ¬ B ) ∧ ( C ∨ D ) ∧ ( ¬ C ∨ ¬ D ) ∧ ( A ∨ C ) ∧ ( ¬ A ∨ ¬ C ) ∧ ( B ∨ D ) ∧ ( ¬ B ∨ ¬ D ) ∧ ( A ∨ D ) ∧ ( ¬ A ∨ ¬ D ) ∧ ( B ∨ C ) ∧ ( ¬ B ∨ ¬ C ) (A ∨ B) ∧ (¬A ∨ ¬B) ∧ (C ∨ D) ∧ (¬C ∨ ¬D) ∧ (A ∨ C) ∧ (¬A ∨ ¬C) ∧(B ∨ D) ∧ (¬B ∨ ¬D) ∧ (A ∨ D) ∧ (¬A ∨ ¬D) ∧ (B ∨ C) ∧ (¬B ∨ ¬C) (AB)(¬A¬B)(CD)(¬C¬D)(AC)(¬A¬C)(BD)(¬B¬D)(AD)(¬A¬D)(BC)(¬B¬C)

伪代码

def DPLL(S):
	if S is empty:
		return ("satisfiable")
	while there is some unit clause {p}, or some pure literal p:
		if {p} and {~p} are both in S:
			return ("unsatisfiable")
		else:
			S = Simplify(S,p)
		if S is empty:
			return ("satisfiable")
		pick some literal p from a shortest clause in S
		if DPLL(Simplify(S,p))=="satisfiable": #Assign it True
			return ("satisfiable")
		else:
			return (DPLL(Simplify(S,~p)) #Assign it False

def Simplify(S,p):
	delete every clause in S containing p
	delete every occurrence in S of ~p
	return (S)

unit clause{p}表示:单逻辑变量语句,即合取范式的析取子句只存在p这一个逻辑变量.
pure literal p表示:在合取范式中p只能以一种方式出现,不能p与﹁p同时出现.

代码实现

合取范式的表示,为了方便程序的编写,所以采取如下的格式表示合取范式:
二皇后的命题逻辑可表示为:
[ [ A , B ] , [ ¬ A , ¬ B ] , [ C , D ] , [ ¬ C , ¬ D ] , [ A , C ] , [ ¬ A , ¬ C ] , [ B , D ] , [ ¬ B , ¬ D ] , [ A , D ] , [ ¬ A , ¬ D ] , [ B , C ] , [ ¬ B , ¬ C ] ] [[A,B],[¬A,¬B],[C,D],[¬C,¬D],[A,C],[¬A,¬C],[B,D],[¬B,¬D],[A,D],[¬A,¬D],[B,C],[¬B,¬C]] [[A,B],[¬A,¬B],[C,D],[¬C,¬D],[A,C],[¬A,¬C],[B,D],[¬B,¬D],[A,D],[¬A,¬D],[B,C],[¬B,¬C]]

import sys
sys.setrecursionlimit(1000000)
import os
import copy
from myarray2d import Array2D
import gc
solution = []
solutions=[]
def DeepCopy(S):#深拷贝
    return copy.deepcopy(S)
def UnitP(S):
    for item in S:
        if item.__len__()==1:
            return True,item[0]
    return False,-1
def NotConflict(S,p):
    listp = []
    listp.append(p)
    listNp = []
    listNp.append(-p)
    if listp in S and listNp in S:
        return False
    return True
def DPLL(S):
    global solution
    #递归出口
    if S.__len__()==0:
        return True
    IsReP, p = UnitP(S)
    #判断是否冲突
    while IsReP:
        if NotConflict(S,p):
            solution.append(p)
            S = Simplify(S,p)
        else:
            return False
        IsReP,p = UnitP(S)
    #再次判断S的大小
    if S.__len__()==0:
        return True
    
    #选取一个长度最小的逻辑子句,并选一个变量
    single = S[0][0]
    min_clause_size = sys.maxsize
    for items in S:
        if min_clause_size > len(items):
            min_clause_size = len(items)
    single = items[0]  # get the first variable
    L = solution.__len__()
    solution.append(single)

    #深拷贝
    temp_S = DeepCopy(S)
    #递归
    if DPLL(Simplify(temp_S,single)):
        return True
    else:
        del solution[L:]
        solution.append(-single)
        temp_S = DeepCopy(S)
        return DPLL(Simplify(temp_S,-single))
def Simplify(S,p):
    for item in S:
        if p in item:
            S.remove(item)
    for item in S:
        if -p in item:
            if item.__len__()==1:
                S.remove(item)
            else:
                item.remove(-p)

    return S


size = 8
line_counter = 0
filein = 'queens{}.in'.format(size)#标记文件,输入
fileout = 'queens{}.out'.format(size)#输出对应的是,不同棋局的行数和列数

template = Array2D(size, size)
for row in range(size):
    for col in range(size):
        template[row, col] = row * size + col + 1#将对应位置的元素用索引进行标记

constraints = []
constraints.remove
#行与行之间用的是合取
# row constraints#行约束
for row in range(size):
    tem=[]
    for col in range(size):
        tem.append(template[row,col])
    constraints.append(tem)#将一行中的索引添加到约束中
    line_counter += 1#行数+1
    for col1 in range(size):#两个元素取反,再析取
        for col2 in range(col1 + 1, size):
            temp = []
            temp.append(-template[row, col1])
            temp.append(-template[row, col2])
            constraints.append(temp)
            line_counter += 1#行数加一
print("行约束")
# column constraints列约束
for col in range(size):
    tem=[]
    for row in range(size):
        tem.append(template[row,col])
    constraints.append(tem)#将一行中的索引添加到约束中
    line_counter += 1
    for row1 in range(size):
        for row2 in range(row1 + 1, size):
            temp = []
            temp.append(-template[row1, col])
            temp.append(-template[row2, col])
            constraints.append(temp)
            line_counter += 1
print("添加列约束")
# main diagonal constraints
# upper triangle
for col in range(size - 2, -1, -1):#对角线约束,从右上角开始,一直到左下角
    for row1 in range(size - col):
        for row2 in range(row1 + 1, size - col):
            temp = []
            temp.append(-template[row1, col+row1])
            temp.append(-template[row2, col+row2])
            constraints.append(temp)
            line_counter += 1
# lower triangle
for row in range(size - 2, 0, -1):#对角线约束,从左上角开始,一直到右下角
    for col1 in range(size - row):
        for col2 in range(col1 + 1, size - row):
            temp = []
            temp.append(-template[row+col1, col1])
            temp.append(-template[row+col2, col2])
            constraints.append(temp)
            line_counter += 1
print("主对角线")
# secondary diagonal constraints
# lower triangle
for col in range(size - 2, -1, -1):
    for row1 in range(size - 1, col - 1, -1):
        for row2 in range(row1 - 1, col - 1, -1):
            temp = []
            temp.append(-template[row1, col+size-1-row1])
            temp.append(-template[row2, col+size-1-row2])
            constraints.append(temp)
            line_counter += 1
# upper triangle
for row in range(1, size - 1):
    for col1 in range(row + 1):
        for col2 in range(col1 + 1, row + 1):
            temp = []
            temp.append(-template[row-col1, col1])
            temp.append(-template[row-col2, col2])
            constraints.append(temp)
            line_counter += 1
print("副对角线")
print(line_counter)
answer = 'DPLLQueensAnswer{}.out'.format(size)
ii=0
while True:
    temp_constraints = DeepCopy(constraints)
    if not DPLL(temp_constraints):
        break
    temp=[]
    for i in range(1,size**2+1):
        if i in solution:
            temp.append(-i)
        else:
            temp.append(i)
    print("temp:",temp)
    print('solution:',end=" ")
    constraints.append(DeepCopy(temp)) 
    for i in solution:
        if i >0:
            print(i,end="  ")
    print()
    solutions.append(temp)
    solution=[]
    ii+=1
print(solutions)
print(ii)
with open(answer,'w') as f:
    f.write(str(ii)+'\n')
    str = ''
    for ans in solutions:
        for item in ans:
            str+='{} '.format(item)
        str+='0\n'
    f.write(str)

myarray2D:请添加图片描述
请添加图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值