回溯算法思想:
回溯算法是深度优先策略的典型应用,回溯算法就是沿着一条路向下走,如果此路不通了,则回溯到上一个分岔路,再选另一条路走,一直这样递归下去,直到遍历所有路径。回溯算法是遍历算法的一种,也是一种暴力解法。
典型应用:
【八皇后问题】在8*8的国际象棋上摆放八个皇后,使其不能互相的攻击。也就是说,任意的两个皇后不能放在同一行、同一个列或者同一个对角线上,问有多少种摆放的方法。
思路:
本算法的思路是按行来规定皇后位置,第一行放置一个皇后,第二行放置一个皇后, 第N行也放置一个皇后… 这样, 可以保证每行都有一个皇后,那么各行的皇后应该放置在哪一列呢, 算法通过循环来完成,在循环的过程中, 一旦找到一个合适的列,则该行的皇后位置确定,则继续进行下一行的皇后的位置的确定。由于每一行确定皇后位置的方式相似,所以可以使用递归法。一旦最后一行的皇后位置确定,则可以得到一组解。找到一组解之后, 之前确定皇后应该放置在哪一列的循环其实才进行了一轮循环, 算法通过该循环遍历所有的列,以此确定每一行所有可能的列的位置。在从一轮循环进入下一轮循环之前,算法需要清除在上一轮被标记为不可放置皇后的标记,也就是回溯。因为进入下一轮循环之后,同一行的皇后的列的位置会发生了变化,之前被标记为不可放置皇后的列和正反对角线位置都已经失效。
import random
# 检查当前皇后的位置与之前的皇后是否冲突
def conflict(state, nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0, nextY-i):
# state[i]-nextX == 0:位于同一列冲突
# state[i]-nextX == nextY-i:位于对角线冲突
return True
return False
# 八皇后问题的回溯算法
# 每行放置一个皇后,对列的位置进行确定
def queens(num, state=()):
for pos in range(num):
if not conflict(state, pos): # 冲突,则回溯到上一层改变皇后的位置
if len(state) == num - 1:
yield (pos, )
else:
for result in queens(num, state+(pos,)): # ?
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__":
print (list(queens(8)))
print("八皇后问题有", len(list(queens(8))), "种解法")
prettyprint(random.choice(list(queens(8))))
运行结果:
[(0, 4, 7, 5, 2, 6, 1, 3), (0, 5, 7, 2, 6, 3, 1, 4), (0, 6, 3, 5, 7, 1, 4, 2),...]
八皇后问题有 92 种解法
. . . X . . . .
. . . . . X . .
X . . . . . . .
. . . . X . . .
. X . . . . . .
. . . . . . . X
. . X . . . . .
. . . . . . X .