LeetCode-DFS模板-求解N皇后和数独问题


适用场景:

输入数据:如果是递归数据结构,如单链表,二叉树,集合,则百分之百可以用深搜;如果是非递归数据结构,如一维数组,二维数组,字符串,图,则概率小一些。
状态转换图:树或者DAG。
求解目标:多阶段存在性问题。必须要走到最深(例如对于树,必须要走到叶子节点)才能得到一个解,这种情况适合用深搜。


dfs模板:

void dfs(input, path, result, cur) {
    if (数据非法) return; // 终止条件
    
    if (cur == input.size()) { // 收敛条件 
        将path放入result
        result.append(list(path))
    }
    
    if (可以剪枝) return;
    
    for(step in range(cur, end)) { // 执行所有可能的扩展动作
        执行动作,修改path 
        dfs(input, path, step + 1 or cur + 1, result);
        恢复path,排列类的题目恢复交换元素
    }
}

1、N皇后问题

皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例:

输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens

def solveNQueens(n):
    """
    :type n: int
    :rtype: List[List[str]]
    """
    # 判断是否冲突
    def is_confict(cur_x, cur_y, pos):
        if cur_x in pos:  # 该行之前放过
            return True
        for y in range(len(pos)):
            x = pos[y]
            if abs(cur_x - x) == abs(cur_y - y): # 斜行放过
                return True
        return False

    # 输出的格式
    def format_out(pos, N):
        res = [""] * N
        for y in range(len(pos)):
            x = pos[y]
            res[x] = "." * y + "Q" + "." * (N - y - 1)
        return res

    def dfs(index, pos, N, res):
        # pos 记录每列皇后的位置
        if index == N:
            res.append(format_out(pos, N))
            return
        for i in range(N):
            if is_confict(i, index, pos):
                continue
            dfs(index + 1, pos + [i], N, res)
        return res

    return dfs(0, [], n, [])

2、数独问题

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sudoku-solver

    def solveSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        def dfs(index, rows, clumns, boxs, board, empty):
            if index == len(empty):
                print("*************************")
                return True
            i, j = empty[index]
            box_index = (i // 3) * 3 + j // 3
            for num in rows[i] & clumns[j] & boxs[box_index]:
                rows[i].remove(num)
                clumns[j].remove(num)
                boxs[box_index].remove(num)
                board[i][j] = str(num)
                if dfs(index+1, rows, clumns, boxs, board, empty):
                    return True
                rows[i].add(num)  # 回溯
                clumns[j].add(num)
                boxs[box_index].add(num)
            return False

        rows = [set(range(1, 10)) for i in range(9)]
        clumns = [set(range(1, 10)) for i in range(9)]
        boxs = [set(range(1, 10)) for i in range(9)]

        empty = []  # 收集需填数位置
        for i in range(9):
            for j in range(9):
                if board[i][j] != '.':  # 更新可用数字
                    num = int(board[i][j])
                    rows[i].remove(num)
                    clumns[j].remove(num)
                    boxs[(i // 3) * 3 + j // 3].remove(num)
                else:
                    empty.append((i, j))

        dfs(0, rows, clumns, boxs, board, empty)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值