八皇后问题简介:
将8个皇后放入8 * 8的棋盘中,任意两个皇后不能在同一条直线或对角线上。(可引申至 n 皇后问题)
示例 - 目标输出结果:
Method - 1
暴力随机法,通过无限随机找到一个符合条件的解:(用到random, copy) 找到一个解的效率很高,但找到全部解方面效率低。
# Method1 - 暴力随机
import random
import copy
dimension = 8
total = 0
# Check if the list satisfy the diagonal requirement
# 检查传入 list 是否满足对角线条件
def conflict(i_list):
list_len = len(i_list)
plus_list = list()
minus_list = list()
for i in range(list_len):
plus_list.append(i_list[i] + i) # 存放 y+x 的值 (Comment: 用 abs() 会更简洁)
minus_list.append(i_list[i] - i) # 存放 y-x 的值
for i in range(list_len - 1): # 如若任何两个 y+x 或 y-x 的值相等,返回冲突
if plus_list[i] == plus_list[i+1]:
return True
if minus_list[i] == minus_list[i+1]:
return True
return False # 反之不冲突
# Generate a list of 8 numbers randomly
# 随机生成一个包含 1-8 的数列(元素不重复)
def generate():
global total
total += 1
v_list = []
r_list = []
for i in range(dimension):
v_list.append(i+1)
for i in range(dimension):
rand_num = random.randint(0, dimension-1-i)
r_list.append(v_list[rand_num])
v_list.remove(v_list[rand_num])
return r_list
# Main part for generate a justified list and display
# 主函数,生成 list 并且画出来
def main():
q_list = generate()
display_str = list()
line = list()
display = list()
for i in range(dimension):
display_str.append('')
line.append(' ')
while conflict(q_list): # 生成合法的 list 其中 index 和 value 分别对应行和 Q 的位置
print('Loop')
q_list = generate()
for i in range(dimension): # 以下是为了方便展示对于 list 的处理
display.append(copy.copy(line))
display[i][q_list[i]-1] = 'Q'
for j in range(0, dimension*2 + 2, 2):
display[i].insert(j, '|')
for c in display[i]:
display_str[i] += c
for i in display_str:
print(i)
print('Number of counts: ', total)
main()
Method - 2
递归筛选法,通过遍历所有位置查找符合的解:在处理找到全部解的问题时会更快。
# Method 2 - 递归求解
import copy
dimension = 8
total = 0
q_list = list()
start = 0
# 接收一个 list 并返回检查值,作用与Method1中相同
def conflict(i_list):
list_len = len(i_list)
plus_list = list()
minus_list = list()
for i in range(list_len):
plus_list.append(i_list[i] + i) # 存放 y+x 的值
minus_list.append(i_list[i] - i) # 存放 y-x 的值
for i in range(list_len - 1): # 如若任何两个元素 y 或 y+x 或 y-x 的值相等,返回冲突
if plus_list[i] == plus_list[i+1]:
return True
if minus_list[i] == minus_list[i+1]:
return True
for i in q_list:
if i_list.count(i) > 1:
return True
return False # 反之不冲突
# 顺序寻找第一个符合要求的Q_list
def queens(row, pos): # row 是判断的行,pos 是该行开始判断的点
global total, q_list, start
total += 1
if row == dimension: # 如果满 8 行输出得到的 list
return q_list
else: # 未满 8 行,判断 list 是否合法
for i in range(pos, dimension): # 从该行检测位置一直检测到 8 如果有合法的值,检测下一行
q_list.append(i)
if not conflict(q_list): # 合法
print('No conflict. Processing to next line. Current list: ', q_list)
return queens(row + 1, 0) # 检测下一行
else: # 不合法,测试下一个位置
print('Conflict occurs. Trying next pos. Current list: ', q_list)
q_list = q_list[:len(q_list)-1]
continue
# 当前行没有合法值,退回前一行或者前两行
start = q_list[-1]
print('No proper value found. Back to check last row.', q_list, ' Start: ', start)
if start < 7: # 如果前一行的已检测到的合法值 < 7, 测试该行下一个位置
start += 1
q_list = q_list[:len(q_list)-1]
return queens(row - 1, start)
else: # 如何前一行的已检测值 = 7,再退回一行,检测该行的下一个位置
start = q_list[-2]
q_list = q_list[:len(q_list)-2]
return queens(row - 2, start + 1)
def main(): # 展示找到的 Q_list
r_list = queens(0, 0)
display_str = list()
line = list()
display = list()
for i in range(dimension):
display_str.append('')
line.append(' ')
print(r_list)
for i in range(dimension): # 以下是为了方便展示对于 list 的处理
display.append(copy.copy(line))
display[i][r_list[i]] = 'Q'
for j in range(0, dimension*2 + 2, 2):
display[i].insert(j, '|')
for c in display[i]:
display_str[i] += c
for i in display_str:
print(i)
print('Number of counts: ', total)
main()