DFS的慢慢参悟和学习过程

Python模板DFS

python的dfs模板
通过做题,让自己对模板有深刻的理解,同时在Python中因为默认的递归深度只有1000,我们可以通过下面操作增加递归深度(否则可能报错提示“maximum recursion depth exceeded incomparison”):

import sys
sys.setrecursionlimit(50000)  #设置递归深度为50000
  1. 其他参数:一般根据题目来进行思考。
  2. 剪枝:通过对一些不必要继续递归的分支,或者提前找到答案之后进行return
  3. 标记状态和恢复状态:每次进行一个新的选择先标记已走过,知道走完不能走了,开始回溯回来之后,再把它恢复成未走过的标记。

常用来解决那些类型的问题

主要操作

  1. 树深度
  2. 子树节点数
  3. 中序、前序、后序输出
  4. 自定义排序
  5. 检查连通性

常见的DFS优化方式(剪枝)

  1. 可行性剪枝:对当前状态进行检查,如果当前条件不合法就不再继续,直接返回。
  2. 搜索顺序剪枝:搜索树有多个层次和分支,不同的搜索顺序会产生不同的搜索树形态。
  3. 最优性剪枝:在最优化问题的搜索过程中,如果当前花费的代价已超过前面搜索到的最优解,那么本次搜索已经没有继续进行下去的意义,停止对当前分支的搜索。
  4. 排除等效冗余:搜索的不同分支,最后的结果是一样的,那么只搜一个分支就够了。
  5. 记忆化搜索:在递归的过程中,有许多分支被反复计算,会大大降低算法的执行效率。将已经计算出来的结果保存起来,以后需要用到的时候直接取出结果,避免重复运算,从而提高了算法的效率。

题目的思考方式(参数的设置)

用一题经典的DFS的题目进行讲解,思考过程直接写在注释里面了
](https://img-blog.csdnimg.cn/2446658a3f1c41d198b50ba55bdda890.png)

# -*- coding: utf-8 -*-
"""
@author: zjh
@time: 2023-04-05 15:05
"""
m, n = map(int, input().split())
mp = [list(map(int, input().split())) for i in range(n)]
vis = [[0] * m for j in range(n)]  #用于标记是否走过
dir_list = [(-1, 0), (1, 0), (0, 1), (0, -1)]  #四个方向的列表定义

"""
思考过程:
1.题目要求左上角的区域和为sum/2,另一半其他的格子也是sum/2,同时问最小的格子数是多少
2.通过题目要求分析dfs需要的参数
    2-1 首先需要尝试各个路径,所以我们需要知道自己的坐标  需要x,y
    2-2 又因为我们需要时刻知道自己目前的和有没有到达目标(sum/2),所以我们用一个current_sum 方便我们记录当前已经累加的和
    2-3 最后题目问我们最小格子数,所以我们需要知道尝试的时候目前走了多少格子 使用cnt进行记录
3.是否有优化空间?
    3-1 一条路径如果已经超过sum/2了,我们就没有必要继续走下去了 提前return
"""

# 矩阵所有元素的和
martix_sum = 0
for i in mp:
    martix_sum += sum(i)
# 记录最小格子数
ans = float('inf')


def dfs(x, y, current_sum, cnt):
    global martix_sum, ans
    if current_sum > martix_sum / 2:
        return
    # 要包含左上角的第一个格子
    if current_sum == martix_sum / 2:
        if cnt < ans and vis[0][0] == 1:
            ans = cnt
        return

    # 进入之后标记已走过
    vis[x][y] = 1
    for u, v in dir_list:
        tx, ty = x + u, v + y
        if 0 <= tx < n and 0 <= ty < m:
            if vis[tx][ty] == 0:
            	#这边用的是current_sum+mp[x][y]是因为下次去的找路径的时候带的是前面算的和,
            	#所以不能是mp[tx][ty]
                dfs(tx, ty, current_sum + mp[x][y], cnt + 1)
    # 恢复原样
    vis[x][y] = 0


dfs(0, 0, 0, 0)
print(ans)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值