Python:ランダムウォークによるエイトクイーンの問題の解決


1エイトクイーンズ問題

8 x 8のチェス盤があり、チェス盤に8つの女王を配置する必要があります。各女王について、行、列、または2つの対角線に他の女王は存在しません。
ここに画像の説明を挿入します
初期状態は[空のボード]と規定されており、アクションは[一度にクイーンなしで左端の列にのみクイーンを配置する]です。このようにして、チェス盤の同じ列に最大で1人の女王が現れることができます。


2プログラムコード

2.1手順1

プログラム1:functions.py。これには、attacked_queens_pairs、display_boardの2つの関数が含まれ、それぞれ[チェス盤に対応するシーケンスの相互に攻撃する女王のペアの数を計算する]と[シーケンスに対応するチェス盤を印刷する]の機能を完了します。次のように:

import numpy as np

def attacked_queens_pairs(seqs, pos):
    """
    计算序列对应棋盘的【互相攻击的皇后对数n】
    因为主程序只在最左面未放置皇后的列上放一个皇后,因此只需检查放置了皇后的前几列
    参数pos的作用是限制只统计前pos列【互相攻击的皇后对数n】
    并且只需要检查当前棋盘的皇后在各自的行和两条对角线上是否有其他皇后
    """
    a = np.array([0] * 81)  # 创建一个有81个0的一维数组
    a = a.reshape(9, 9)  # 改为9*9二维数组。为方便后面使用,只用后八行和后八列的8*8部分,作为一个空白棋盘
    n = 0  # 互相攻击的皇后对数初始化为0

    for i in range(1, pos+1):
        a[seqs[i - 1]][i] = 1  # 根据序列的前pos个数,按从第1列到pos列的顺序,在空白棋盘对应位置放一个皇后,生成当前序列对应的棋盘

    for i in range(1, pos+1): # 只统计前pos列【互相攻击的皇后对数n】
        for k in list(range(1, i)) + list(range(i + 1, 9)):  # 检查每个皇后各自所在的行上是否有其他皇后
            if a[seqs[i - 1]][k] == 1:  # 有其他皇后
                n += 1
        t1 = t2 = seqs[i - 1]
        for j in range(i - 1, 0, -1):  # 看左半段的两条对角线
            if t1 != 1:
                t1 -= 1
                if a[t1][j] == 1:
                    n += 1  # 正对角线左半段上还有其他皇后

            if t2 != 8:
                t2 += 1
                if a[t2][j] == 1:
                    n += 1  # 次对角线左半段上还有其他皇后

        t1 = t2 = seqs[i - 1]
        for j in range(i + 1, 9):  # 看右半段的两条对角线
            if t1 != 1:
                t1 -= 1
                if a[t1][j] == 1:
                    n += 1  # 正对角线右半段上还有其他皇后

            if t2 != 8:
                t2 += 1
                if a[t2][j] == 1:
                    n += 1  # 次对角线右半段上还有其他皇后
    return int(n/2)  # 返回n/2,因为A攻击B也意味着B攻击A,因此返回n的一半

def display_board(seqs):
    """
     显示序列对应的棋盘
    """
    board = np.array([0] * 81)  # 创建一个有81个0的一维数组
    board = board.reshape(9, 9)  # 改变为9*9二维数组,为了后面方便使用,只用后八行和后八列的8*8部分,作为一个空白棋盘

    for i in range(1, 9):
        board[seqs[i - 1]][i] = 1  # 根据序列,从第一列到最后一列的顺序,在对应位置放一个皇后,生成当前序列对应的棋盘
    print('对应棋盘如下:')
    for i in board[1:]:
        for j in i[1:]:
            print(j, ' ', end="")  # 有了end="",print就不会换行
        print()  # 输出完一行后再换行,这里不能是print('\n'),否则会换两行
    print('攻击的皇后对数为' + str(attacked_queens_pairs(seqs,8)))

このプログラムには出力がありませんが、メインプログラムが呼び出す2つの関数が定義されています。

2.2手順2

プログラム2:main.py。メインプログラムは、プログラム2の2つの関数を呼び出すことにより、ランダムウォークのプロセス全体を完了して8つのクイーンの問題を解決します。次のように:

import random
from functions import attacked_queens_pairs, display_board

seqs = [0] * 8 # 初始化序列
flag = 0 # 失败标志

for i in range(8):
    nums = list(range(1, 9)) # 从nums中选择在当前列放置皇后的位置
    if flag == 1: # 失败则结束循环
        break
    while True:
        try:
            temp = random.choice(nums) # 随机挑选,即随机游走
            seqs[i] = temp # 暂时将皇后放在当前列的第temp行
            nums.remove(temp) # 从nums移除已产生的随机数
            if attacked_queens_pairs(seqs, i+1) == 0: # 将皇后放在当前列的第temp行后,若已放置皇后的前i+1列中无互相攻击的皇后,则进行下一列位置的选择
                break
        except IndexError:
            print('本次计算失败,请重新运行本程序!')
            flag = 1 # 已失败
            break

if flag == 0:
    print('已找到解序列:' + str(seqs))
    display_board(seqs)

1つの出力は次のとおりです。

已找到解序列:[7, 1, 3, 8, 6, 4, 2, 5]
对应棋盘如下:
0  1  0  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  1  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  0  0  0  0  1  
0  0  0  0  1  0  0  0  
1  0  0  0  0  0  0  0  
0  0  0  1  0  0  0  0  
攻击的皇后对数为0

別の出力は次のとおりです。

本次计算失败,请重新运行本程序!

上記の出力には2つのタイプがあります。1つは理解シーケンスを見つけることであり、2つ目は見つかりません。アルゴリズムは現在の列の任意の位置にクイーンをランダムに配置するため、配置されたクイーンの最初の数列にクイーンがない場合は、次の列の位置が選択されるため、プロセスは[適切ではありません配置する位置]状態は失敗と宣言する必要があり、プログラムを再実行することによってのみ再調査できます。


3件のレビュー

メインプログラムは短くて理解しやすいですが、解決策を得るために何度か実行する必要があるかもしれません。失敗が原因でない場合は、もう一度実行してください。


終わり

おすすめ

転載: blog.csdn.net/qq_40061206/article/details/111729406