算法综述
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)
(A∨B)∧(¬A∨¬B)∧(C∨D)∧(¬C∨¬D)∧(A∨C)∧(¬A∨¬C)∧(B∨D)∧(¬B∨¬D)∧(A∨D)∧(¬A∨¬D)∧(B∨C)∧(¬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: