1.计算冲突
之前有疑惑的地方:
state是一个元组,储存每一行的皇后的列索引
计算下一个皇后和当前的皇后是否冲突,在同一列上,列差为0,在斜杠上列差的绝对值等于下一行减去当前行,如果满足这两点则返回true,否则返回false
def conflict(state, nextColumn):
nextRow = rows = len(state)
for row in range(rows):
column = state[row]
if abs(column - nextColumn) in (0, nextRow - row):
"""
如果差值等于0,两个皇后在同一列, 则代表冲突, 返回True;
如果列的差值等与行的差, 两个皇后在对角线上, 则代表冲突, 返回True;
"""
return True
return False
2.生成皇后的位置,这里传入两个参数,一个是空的皇后的列索引,还有就是皇后的数量
循环皇后在列上的位置,0-7,
通过传入state(即皇后的列索引/位置)和当前皇后的pos即位置,去计算是否冲突,如果不冲突则进入下一步,
判断是否是最后一个皇后即len(state)==num-1(是否已经有7个列索引了),如果是最后一个皇后,因为已经判断过冲突了,所以剩下的就是结果了,这个语句也是递归的出口
如果不是最后一个皇后,则进入else,第一层的queens已经生成了一个皇后的位置,则这时候传入新的state和num去调用queens,知道调用到最后一个皇后,就会触发递归的回操作,最后再pos+result就是全部皇后的列索引/位置
def queens(num, state=()):
"""
采用生成器的方式来产生每一个皇后的位置,并用递归来实现下一个皇后的位置。
num: 皇后的数量
state: 标记已经排好的每个皇后的位置
"""
for pos in range(num): # 八皇后的数量N=0, 1, 2, 3, 4, 5, 6 , 7 你要在哪一列放置皇后
# 如果不冲突,则递归构造棋盘。
if not conflict(state, pos): # 回溯法的体现
# 如果棋盘状态state已经等于num-1,即到达倒数第二行,而这时最后一行皇后又没冲突,直接yield,打出其位置(pos, )
if len(state) == num - 1: # state=()
yield (pos,)
else: # (0, )
for result in queens(num, state + (pos,)):
yield (pos,) + result
3.打印皇后
def prettyprint(solution):
“”"
友好展示: 为了直观表现棋盘,用X表示每个皇后的位置
“”"
def line(pos, length=len(solution)):
return ' . ' * (pos) + ' x ' + ' . ' * (length - pos - 1)
for pos in solution:
print(line(pos))
4.测试
if __name__ == '__main__':
solutions = queens(8)
for index, solution in enumerate(solutions):
print("第%d种解决方案:" % (index + 1), solution)
prettyprint(solution)
print('*' * 100)
完整代码
#计算冲突,计算当前皇后之前的每一个皇后的列索引是否冲突,即是否在一列上或者一个斜线上
def conflict(state,nextcolumn):
nextrow=rows=len(state)
for row in range(rows): #遍历每一个皇后
column=state[row] #获得每一个皇后的列索引
if abs(nextcolumn-column) in (0,nextrow-row): #计算是否冲突
return True
return False
#生成皇后
def queens(num,state=()): #state是用来存放所有皇后的列索引的即位置
for pos in range(num): #pos是皇后的每个列索引位置
if not conflict(state,pos): #计算这个皇后的位置跟之前的皇后的位置是否冲突
if len(state)==num-1: # 如果state的长度等于num-1,说明已经有num-1个皇后的位置了,
# 现在已经在生成最后一个皇后的位置了,并且这个位置跟之前皇后的位置还不冲突,
# 可以直接生成这个pos即最后一个皇后的列索引/位置
yield (pos,) #这个分支是递归出口
else: #如果不是最后一个皇后则运行else分支
for result in queens(num,state+(pos,)): #因为已经经过了冲突计算,说明这个皇后的列索引与之前的皇后的列索引不冲突,
# 添加到state里,再传递更新后的state去遍历下一个皇后
yield (pos,)+result
#绘制棋盘
def prettyprint(solution):
def line(pos,length=len(solution)):
return '.'*pos+'X'+'.'*(length-pos-1)
for pos in solution:
print(line(pos))
#测试
if __name__=='__main__':
solutions=queens(4)
for index,solution in enumerate(solutions):
print('第%d种解法:'%(index+1),solution)
prettyprint(solution)
print('*'*100)
把所有步骤都用类封装起来,这样调用的时候就更加简便了
#封装类的方法解决八皇后的问题
class Solution:
def solve(self,num):
self.state=()
for solution in self.queen(self.state,num):
self.printqueen(solution,num)
def conflict(self,state,nextcolumn): #冲突计算
rows=nextrows=len(state)
for row in range(rows):
column=state[row]
if abs(column-nextcolumn) in (0,nextrows-row):
return True
return False
def queen(self,state,num): #生产皇后
for pos in range(num): #该皇后的列索引
if not self.conflict(state,pos):
if len(state)==num-1:
yield (pos,)
else:
for result in self.queen(state+(pos,),num):
yield (pos,)+result
def printqueen(self,solution,num): #打印棋盘
print(solution)
for row in range(num):
line=""
for column in range(num):
if solution[row]==column:
line+="Q\t"
else:
line+="*\t"
print(line,"\n")
print("\n")
print("*"*100)
s=Solution()
solutions=s.solve(4)