【问题标题】:How recursion worked in n_queen Python递归如何在 n_queen Python 中工作
【发布时间】:2017-11-19 23:56:30
【问题描述】:

我正在尝试解决 python 中的经典 n Queen 问题。不幸的是,输出与我的预期完全不同。我了解回溯算法,但可能不清楚在编写递归时可能会出错的地方。我尝试了 1.print 一种可能的解决方案。 2. 打印所有可能的解决方案。 (这里我的解决方案被记为 n 的列表,其中 list[i] 的值是第 i 行上的选定列)

def n_queen_find1(n):
    answer = [-1] * n
    def dfs(depth,answer):   
        if depth == n:
            print ("cur valid answer is ",answer)
            return answer
        else:
            for colNum in range(n): # check every col at cur depth
                if is_safe(depth,colNum,answer):
                    answer[depth] = colNum
                    print ("now the answer is ", answer)
                    print ("now depth move to ", depth + 1)
                    dfs(depth + 1,answer)

    def is_safe(i,j,answer_cur):
        # given current queen placement , could we place the ith queen (at row i) at the col j
        for prerow in range(i):
            if answer_cur[prerow] == j or abs(prerow - i) == abs(answer_cur[prerow] - j):
                return False
        return True

    return dfs(0,answer)

我希望 n_queen_find1 在 n == 4 时输出 4 个元素的列表,例如 [1, 3, 0, 2]。在我的递归过程中,生成了正确的答案(如打印中所示)。但是,该函数什么也没返回。我添加了那些有助于调试的打印行,发现我不明白为什么在创建第一个正确答案时 dfs 没有停止并返回?

trial1 = n_queen_find1(4)
print trial1
('now the answer is ', [0, -1, -1, -1])
('now depth move to ', 1)
('now the answer is ', [0, 2, -1, -1])
('now depth move to ', 2)
('now the answer is ', [0, 3, -1, -1])
('now depth move to ', 2)
('now the answer is ', [0, 3, 1, -1])
('now depth move to ', 3)
('now the answer is ', [1, 3, 1, -1])
('now depth move to ', 1)
('now the answer is ', [1, 3, 1, -1])
('now depth move to ', 2)
('now the answer is ', [1, 3, 0, -1])
('now depth move to ', 3)
('now the answer is ', [1, 3, 0, 2])
('now depth move to ', 4)
('cur valid answer is ', [1, 3, 0, 2])
('now the answer is ', [2, 3, 0, 2])
('now depth move to ', 1)
('now the answer is ', [2, 0, 0, 2])
('now depth move to ', 2)
('now the answer is ', [2, 0, 3, 2])
('now depth move to ', 3)
('now the answer is ', [2, 0, 3, 1])
('now depth move to ', 4)
('cur valid answer is ', [2, 0, 3, 1])
('now the answer is ', [3, 0, 3, 1])
('now depth move to ', 1)
('now the answer is ', [3, 0, 3, 1])
('now depth move to ', 2)
('now the answer is ', [3, 0, 2, 1])
('now depth move to ', 3)
('now the answer is ', [3, 1, 2, 1])
('now depth move to ', 2)
None

我稍微修改了 n_queen_find1 以生成所有可能的解决方案,但我也无法解释输出。

def n_queen_findall(n):
    answer = [-1] * n
    finalAnswer = []
    def dfs(depth,answer,finalAnswer):   
        if depth == n:
            print ("cur valid answer is ",answer)            
            finalAnswer.append(answer)
            print ("after appending final answer is ", finalAnswer)
            return
        else:
            for colNum in range(n): # check every col at cur depth
                if is_safe(depth,colNum,answer):
                    answer[depth] = colNum
                    print ("now the answer is ", answer)
                    print ("now depth move to ", depth + 1)
                    dfs(depth + 1,answer,finalAnswer)

    def is_safe(i,j,answer_cur):
        # given current queen placement , could we place the ith queen (at row i) at the col j
        for prerow in range(i):
            if answer_cur[prerow] == j or abs(prerow - i) == abs(answer_cur[prerow] - j):
                return False
        return True
    dfs(0,answer,finalAnswer)
    return finalAnswer

这是我对 n_queen_findall 的测试。它也不正确。首先,当深度不等于 n 时,为什么 finalAnswers 会附加结果?二、为什么finalAnswer有重复?

trial2 = n_queen_findall(4)
print trial2
('now the answer is ', [0, -1, -1, -1])
('now depth move to ', 1)
('now the answer is ', [0, 2, -1, -1])
('now depth move to ', 2)
('now the answer is ', [0, 3, -1, -1])
('now depth move to ', 2)
('now the answer is ', [0, 3, 1, -1])
('now depth move to ', 3)
('now the answer is ', [1, 3, 1, -1])
('now depth move to ', 1)
('now the answer is ', [1, 3, 1, -1])
('now depth move to ', 2)
('now the answer is ', [1, 3, 0, -1])
('now depth move to ', 3)
('now the answer is ', [1, 3, 0, 2])
('now depth move to ', 4)
('cur valid answer is ', [1, 3, 0, 2])
('now the final answer is ', [])
('now the answer is ', [2, 3, 0, 2])
('now depth move to ', 1)
('now the answer is ', [2, 0, 0, 2])
('now depth move to ', 2)
('now the answer is ', [2, 0, 3, 2])
('now depth move to ', 3)
('now the answer is ', [2, 0, 3, 1])
('now depth move to ', 4)
('cur valid answer is ', [2, 0, 3, 1])
('now the final answer is ', [[2, 0, 3, 1]])
('now the answer is ', [3, 0, 3, 1])
('now depth move to ', 1)
('now the answer is ', [3, 0, 3, 1])
('now depth move to ', 2)
('now the answer is ', [3, 0, 2, 1])
('now depth move to ', 3)
('now the answer is ', [3, 1, 2, 1])
('now depth move to ', 2)
[[3, 1, 2, 1], [3, 1, 2, 1]]

抱歉把问题问的这么长。这个问题的原因可能很简单。我是python的初级,尤其是python后端。也许我对python通过引用传递的理解不正确?非常感谢对此的一些指导。提前非常感谢。

【问题讨论】:

  • 感谢您的评论。 if 条件中的abs(prerow - i) == abs(answer_cur[prerow] - j) 用于检查对角线。在is_safe 函数中,检查了两件事,1) 列冲突 2) 对角线冲突。默认情况下,它不检查行,因为它们在不同的行中。

标签: python recursion n-queens


【解决方案1】:

在您的dfs 中,只有当 n==4 时,您才会有 return,但当 n 是其他任何东西时,则不会。所以无论dfs4返回什么,它们都会被父被调用者吸收,最终什么都不会返回。

因此,为了解决您的第一个问题,因为我们知道答案中的失败展示位置返回 None,(因为 for 中的 if 循环在 else 内将失败),我们在递归 dfs 之前添加一个 if检查成功。如果是这样,我们返回answer。所以只要改变这个:

dfs(depth + 1,answer)

到这里:

if dfs(depth + 1,answer): #false i.e None for failed dfs
    return answer

在我们解决第二个问题之前,让我们想想,如果我们有 5 个解决方案,我们需要 5 个数组来存储它们,对吗?你有多少?一个answer。在finalAnswer.append(answer) 中,您不会添加包含数组的较新解决方案,您只是添加旧answerreference,它会不断被修改,而您打算添加的任何内容都会丢失。

因此您需要在追加之前复制并创建新数组。此外,您还需要摆脱上述return

def n_queen_find1(n):
    answer = [-1] * n
    finalAnswer = []
    def dfs(depth,answer):
        if depth == n:
            print ("cur valid answer is ",answer)
            finalAnswer.append([i for i in answer]) #answer is copied
            return answer
        else:
            for colNum in range(n): # check every col at cur depth
                if is_safe(depth,colNum,answer):
                    answer[depth] = colNum
                    #print ("now the answer is ", answer)
                    #print ("now depth move to ", depth + 1)
                    dfs(depth + 1,answer)


    def is_safe(i,j,answer_cur):
        # given current queen placement , could we place the ith queen (at row i) at the col j
        for prerow in range(i):
            if answer_cur[prerow] == j or abs(prerow - i) == abs(answer_cur[prerow] - j):
                return False
        return True

    dfs(0,answer)
    return finalAnswer

哪个打印:

cur valid answer is  [1, 3, 0, 2]
cur valid answer is  [2, 0, 3, 1]
[[1, 3, 0, 2], [2, 0, 3, 1]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2018-03-18
    • 2017-03-19
    • 2016-10-05
    • 1970-01-01
    相关资源
    最近更新 更多