八皇后问题是经典回溯算法例题,用“暴力搜索”的方法求解。 在Leetcode描述为:https://leetcode-cn.com/problems/eight-queens-lcci/

设计一种算法,打印 8皇后在 8 × 8 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线

由八皇后问题可以推广至N皇后问题。

咱们先以4皇后来进行思考:

--Q-
Q---
---Q
-Q--

 以每个皇后Q为中心,“进行米”字威胁,要求皇后们两两不威胁。所以要求任意2个皇后Q,不同行不同列也不同对角线。

思考:咱们需要逐个位置地填“Q”来验证当前位置是否适合放“Q”。比如,在(0, 0)放Q,我们并不知道是否合理,需要继续放,直到某一行完全没有合适的位置,我们才知道前面有问题

用回溯算法构思:

依次遍历第一排的4个位置,然后推测出第二排可能的位置,继续往下推测,直到无解或者找到答案就返回

咱们用“递归”直接实现上面画的树状结构就可以完成题解了

1. 每递归一次,就处理下一级节点;

2. 处理当级节点时,依次填位置([0, 1, 2, 3])并判断是否有效。如果有效,则进入下一级节点;若无效,则返回。

3. 判断停止:如果咱们处理到row3(也就是第4级节点),与棋盘的行数一致,并且有解,则代表已经得出一组解了。

# author: muzhan

C = 0

def run(num=8):
    result = [-1] * num
    row = 0
    backtrack(result, row)

def backtrack(result, row):
    n = len(result)
    if row == n:
        global C
        C += 1
        print(result)
        return
    for i in range(n):
        result[row] = i
        if isvalid(result, row):
            backtrack(result, row+1)

def isvalid(ans, pos):
    valid = True
    for i in range(pos):
        diag = pos - i
        if ans[pos] in [ans[i], ans[i] - diag, ans[i] + diag]:
                valid = False
                break
    return valid



if __name__ == '__main__':
    run(num=8)
    print('solution num:', C)

总结

对于回溯算法的一般解体方法:

1. 画出一个树状图,确定多级节点;

2. 写出有效性判断函数isvalid();

3. 用递归backtrack(i+1)的形式向下追溯节点。 

 


对于leetcode题的解法https://leetcode-cn.com/problems/eight-queens-lcci/

class Solution:
    def __init__(self):
        self.ans_set = []

    def isvalid(self, ans, pos):
        valid = True
        for i in range(pos):
            diag = pos - i
            if ans[pos] in [ans[i], ans[i]-diag, ans[i]+diag]:
                valid = False
                break
        return valid
    
    def backtrack(self, ans, pos):
        n = len(ans)
        if n == pos:
            board = []
            for i in ans:
                row = ["."] * n
                row[i] = "Q"
                board.append(''.join(row))
            self.ans_set.append(board)
            return
        for i in range(n):
            ans[pos] = i
            if self.isvalid(ans, pos):
                self.backtrack(ans, pos+1)


    def solveNQueens(self, n: int) -> List[List[str]]:
        result = [-1] * n
        row = 0
        self.backtrack(result, row)
        return self.ans_set

击败了30%,待优化...

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐