【问题标题】:Queens on chessboard solved randomly in Python棋盘上的皇后在 Python 中随机解决
【发布时间】:2017-05-31 16:06:20
【问题描述】:

这个想法是尝试通过将皇后完全随机地放置在棋盘的每一行中来尝试解决“皇后问题”,并查看解决它需要多少次重复。棋盘可以是任意大小。

我的想法是创建 s 个列表,每个列表包含 s 个“空”字符(下划线)。然后为每一行随机选择一个位置来插入女王(“I”值),然后标记下面和对角向下的所有位置(我将逐行进行,所以我不必为上面的行而烦恼) 与 X。如果在任何迭代中随机选择的皇后位置与该行中任何 X 的位置匹配,我从头开始新的棋盘。

我有类似的东西,但它似乎卡在第 19 行(标有注释),但它没有给我任何错误。有什么问题?另外,我的解决方案(除了那条线)是否正确?

from random import *


#Success flag
success = 0

#Trials counter
trials = 0


s = input ("enter board size\n")
s = int(s)
block = 1 #blockade
queen = 2 #queen
board = [[0 for x in range(s)] for y in range(s)] 

while success == 0:
    for y in range (0, s-1):
        pos = randint(0,s-1)    #line 19
        if board[y][pos] != block:
            board[y][pos] = queen
            a = 1
            for z in range (y, s-2):
                board[z + 1][pos] = block
                if pos - a >= 0:
                    board[z + 1][pos - a] = block
                if pos + a <= s-1:
                    board[z + 1][pos + a] = block
                a = a + 1
            success = 1
        else:
            success = 0


#Printing board
for y in range (0, s-1):
    print (board[y])

print ("Number of trials:\n")
print (trials)

【问题讨论】:

  • “请完成我的代码”不是问题。
  • 我一直在处理代码和帖子。我希望现在好些了吗?
  • 似乎太复杂了。放置的皇后自然由一对数字表示,例如(2,3) 表示第 2 行第 3 列。给定 2 个皇后 (a,b) 和 (c,d),很容易判断它们是否可以互相攻击,而无需“标记”每个皇后攻击的所有方格。如果它们在同一行或同一列上,则微不足道。对于对角线的情况——只需计算连接皇后的线的斜率。是+/- 1吗?如果是这样 - 他们可以攻击。
  • 如果您真的开始随机放置皇后直到找到解决方案,您的程序可能不会在宇宙不复存在之前停止。您正在查看 64^8 = 281474976710656 个可能的完全随机的皇后位置,其中只有 92 个是解决方案
  • @IrmendeJong 我认为您误读了“将皇后完全随机放置在棋盘的每一行”的问题(强调我的)。你让我很好奇。我刚刚实现了它,并且能够在几秒钟内得到解决方案。甚至随机放置 8 也不是没有希望的:64 选择 8 = 4426165368 并将其除以 92 表明,平均而言,棋盘上 8 个不同位置的大约 5000 万个选择中的 1 个将是一个解决方案。

标签: python random n-queens


【解决方案1】:

一些问题:

  • range 函数的第二个参数代表第一个不会被访问的数字,所以大多数时候你只需要一个短数字。
  • 您需要在尝试失败时退出 y 上的循环:您不想继续下一行,而是重新启动
  • 您需要在每次尝试失败后重置电路板,或者在每次尝试之前设置:
  • 如果在多次迭代后没有找到解决方案,您应该建立一些安全退出,否则您可能会遇到卡住的风险。对于输入 1、2 或 3,没有解决方案。
  • 试验次数永远不会增加
  • 与其盲目选择位置,不如只从可用位置中选择(不被阻止),否则您将进行惊人数量的试验:对于尺寸 8,需要 100 并不罕见000 次试验没有进行这种过滤!

查看更正后的代码,以及我进行更改的 cmets:

import random

s = input ("enter board size\n")
s = int(s)
trials = 0
block = 1
queen = 2
# add some maximum to the number of attempts
max_trials = 100000 
success = 0

# add safety measure to avoid infinite looping
while success == 0 and trials <= max_trials:
    # initialise board before every trial
    board = [[0 for x in range(s)] for y in range(s)]
    # assume success until failure
    success = 1
    # count trials
    trials += 1 
    for y in range (0, s): # use correct range
        # get the fields that are still available in this row
        available = [x for x, i in enumerate(board[y]) if i == 0]
        if len(available) == 0:
            success = 0
            # exit for loop, you want to start a next trial
            break
        # choose a random position among available spots only
        pos = available[random.randint(0, len(available)-1)]    
        board[y][pos] = queen
        a = 1
        for z in range (y+1, s): # use correct range
            board[z][pos] = block
            if pos - a >= 0:
                board[z][pos - a] = block
            if pos + a < s:
                board[z][pos + a] = block
            a = a + 1

for y in range (0, s): # use correct range
    print (board[y])

print ("Number of trials:", trials)

看到它在repl.it上运行

【讨论】:

    【解决方案2】:

    这是一个基于对放置的皇后坐标进行算术运算的简短解决方案:

    import random, itertools
    
    def clashes(p,q):
        a,b = p
        c,d = q
        return a == c or b == d or abs(a-c) == abs(b-d)
    
    def solution(queens):
        #assumes len(queens) == 8
        return not any(clashes(p,q) for p,q in itertools.combinations(queens,2)) 
    
    def randSolve():
        counter = 0
        while True:
            counter += 1
            queens = [(i,random.randint(1,8)) for i in range(1,9)]
            if solution(queens): return counter, queens
    
    print(randSolve())
    

    我上次运行它时得到了:

    (263528, [(1, 4), (2, 7), (3, 3), (4, 8), (5, 2), (6, 5), (7, 1), (8, 6)])
    

    表示第一个解决方案是在 263527 次失败后遇到的。平均而言,您可能会经历 182360 次失败,然后才能获得成功。

    【讨论】:

      【解决方案3】:

      在你尝试不同的行并且这次失败之后,你必须创建一个新的空板,如果成功为0,你应该如下打破for循环。

      while success == 0:
          board = [[0 for x in range(s)] for y in range(s)]
          for y in range (0, s):
              pos = randint(0,s-1)    #line 19
              if board[y][pos] != block:
                  board[y][pos] = queen
                  for i in range(y+1, s):
                      board[i][pos] = block
                  success = 1
              else:
                  success = 0
                  break
          trials += 1
      

      您可以按照相同的逻辑来实现对角线的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-14
        • 1970-01-01
        • 1970-01-01
        • 2019-05-11
        • 2020-01-10
        • 2021-08-23
        • 1970-01-01
        • 2017-05-27
        相关资源
        最近更新 更多