Python算法之试探算法思想——解决“八皇后问题”

试探算法思想:先暂时放弃关于问题规模大小的限制,并将候选解按照某一顺序逐一枚举和检验

算法步骤

  1. 针对所给问题定义解空间
  2. 确定易于搜索的解空间结构
  3. 以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索

例题

八皇后问题:在8*8的国际象棋上摆放8个皇后,使其不能相互攻击,即任意两个皇后都不能处在同一行同一列或同一斜线上,问有多少种解法:

本题思路:

  1. 确定解空间:使用x来存储一条解空间,由于每行(或每列)都有且只能有一个皇后,因此存储时使用一个一维列表即可存储解,即x = [x0,x1,x2,x3,x4,x5,x6,x7],其中xi的值代表第i行中的第多少列。all_x则代表所有的可行解。
  2. 定义一个confict(k)函数,该函数通过可以检测前k项是否冲突,定义一个queen(k)函数,该函数通过递归,通过深度优先搜索算法,从一行开始由小到大遍历,并在遍历过程中使用confict(k)函数检测是否有冲突,进行剪枝操作。
n = 8
x = []  # 一个解
all_x = []  # 一组解
# 判断前k项是否冲突
def conflict(k):
    global x
    for i in range(k):  # 遍历前x[0]~x[k-1]
        if x[i] == x[k] or abs(x[i]-x[k]) == abs(i-k):
            return True
    return False

def queen(k):
    global n, x, all_x
    if k >= n:  # 超出最底行
        # 此处注意深浅拷贝
        all_x.append(x[:])
        # 如果使用X.append(x)的话,将会出现[[][]···[]]的情况。
    for i in range(n):
        x.append(i)
        if not conflict(k):   # 剪枝(如果没有冲突的话,则开始下一列)
            queen(k+1)     # 此处使用递归
        x.pop()  # 回溯,出栈

# 解的可视化
def show(x):
    global n
    for i in range(n):
        print('O'*(x[i]) + 'X'+'O'*(n-x[i]-1))
# 测试
queen(0)  # 从第0行开始
print("总共有%d种情况" % (len(all_x)))
print(all_x[0])
show(all_x[0])

突发奇想:
对于k皇后问题情况分布是如何的呢?
不妨测试一下:

for i in range(4, 11):
    n = i
    x = []  # 一个解
    all_x = []  # 一组解
    queen(0)  # 从第0行开始
    print("K = %d时,总共有%d种情况" % (i,len(all_x)))
    # print(all_x[0])

结果如下:
K = 4时,总共有2种情况
K = 5时,总共有10种情况
K = 6时,总共有4种情况
K = 7时,总共有40种情况
K = 8时,总共有92种情况
K = 9时,总共有352种情况
K = 10时,总共有724种情况
貌似也没有看出什么规律。
【题材来源:Python算法详解,张玲玲,人民邮电出版社P42】

猜你喜欢

转载自blog.csdn.net/weixin_45915507/article/details/114312309
今日推荐