【蓝桥杯笔记】DFS专项学习

dfs通常与“递归+循环”一起使用,所以要以“递归”的眼光去遍历所有可能的方案或者路径

1. 一个问题的解可以分解为若干个子问题的解,即存在某种递归公式。

2.递归的终止条件

3. 翻译成递归代码。 

除此之外,为了避免重复计算,可以利用数组来保存过去已经计算好的值,在下一次使用时直接调用即可;该方法称之为“记忆性递归”

其相比简单的递归,可以减少时间复杂度,本质是用空间换时间。


【第五届:地宫取宝】

1. 递归公式

dfs(x_{i+1},y_{i+1},z_{i+1},w_{i+1})=dfs(x_{i},y_{i},z_{i}+1,w_{i}+v)      ——选

dfs(x_{i+1},y_{i+1},z_{i+1},w_{i+1})=dfs(x_{i},y_{i},z_{i},w_{i})        ——不选

2. 终止条件

已经到达出口,

①若拿到的宝物数满足数量,则返回 1,路径存在;②否则,返回 0,路径不存在。

3. 代码
n, m, k = map(int, input().split())
mp = [list(map(int, input().split())) for i in range(n)]

# 记忆性缓存,提高函数递归时的性能
from functools import lru_cache
@lru_cache(maxsize=None)
def dfs(x, y, z, w): # z: 先前拿的宝物数量 w: 先前拿的宝物的最大价值
    if x == n-1 and y == m-1:
        if z == k:
            return 1
        if z == k - 1 and w < mp[x][y]:
            return 1
        return 0

    ans = 0
    # (dx, dy)=(1,0):向右走    (dx, dy)=(0,1):向下走
    for dx, dy in [(1, 0), (0, 1)]:
        # 每个位置可有两个选择 更新坐标
        nx = x + dx
        ny = y + dy
        if nx < n and ny < m:
          # 总次数为选择+不选择
            ans += dfs(nx, ny, z, w) # 当前不选择宝物,走到 (nx,ny)
            if w < mp[x][y]: # 当前选择宝物,走到 (nx,ny)
                ans += dfs(nx, ny, z + 1, mp[x][y])
            ans %= 10 ** 9 + 7
            
    return ans

print(dfs(0, 0, 0, -1))

 【第十四届:分糖果】

1. 递归公式

dfs(one_{i+1},two_{i+1},people_{i+1})=dfs(one_{i}-j,two_{i}-k,people_{i})

2. 终止条件。

糖果已经分给了7个人,

①所有糖果都分完了,该路径存在;②否则,该路径不存在。

3. 代码。
def dfs(numOne, numTwo, numPeople):
    # 分的人数够7人了,说明分完了
    if numPeople == 7:
        if numOne==0 and numTwo==0:
            return 1
        return 0
    
    ans = 0    
    for j in range(numOne+1):  #第一种糖果
        for k in range(numTwo+1):     #第二种糖果
            if j+k >=2 and j+k <= 5:
                ans += dfs(numOne-j,numTwo-k,numPeople+1)
    return ans

print(dfs(9, 16, 0))

【第十四届:飞机降落】

1. 递归公式。

dfs(a_{i+1},b_{i+1})=dfs(a_{i}+1,max(b_{i},t[i])+l[i])

2. 终止条件。

所有的飞机都能够顺利着陆,则成功;并不需要飞机着陆的方案。

3. 代码。
# a代表飞机数,b代表当前时间
def dfs(a, b):  
    # 设置为全局变量
    global flag
    if a==n:    #如果飞机能开到n+1架,说明已经成功
        flag = True
        return
    if flag:
        return
    
    for i in range(n):
        if visited[i]==0:
            if t[i]+d[i]<b:
                flag = False
                return
            visited[i] = 1
            dfs(a+1, max(b,t[i])+l[i])
            visited[i] = 0


n = int(input())
# 防止越界
t=[0]*15 
d=[0]*15
l=[0]*15
for i in range(n):
    # 输入每组数据
    groupNum = int(input())
    
    word = 1
    for j in range(groupNum):
        # 每架飞机的 降落时刻区间 & 落地时刻区间
        t[j], d[j], l[j] = map(int, input().split())
    # 标记所有的飞机安全降落
    flag = False
    visited = [0]*15
    dfs(0,0)
    if flag:
        print("YES")
    else:
        print("NO")

【第十四届:异或和】

1. 递归公式。

dfs(pos_{i})=dfs(pos_{i-1})  

若该结点仍有子结点,则继续深度搜索。

2. 终止条件。

到底叶子结点处。

3. 代码。
import sys

def dfs(pos):
    global ans
    # 终止条件:叶子结点
    if relations[pos]==[]:
        return 
    for t in relations[pos]:
        ans ^= weighted[t]
        dfs(t)

# 输入数据
n, m = map(int, input().split())
weighted = [0] + [x for x in map(int, input().split())]
relations = [[] for _ in range(n+1)]
for i in range(n-1):
    i, j = map(int, input().split())
    if i<j:
        relations[i].append(j)
    else:
        relations[j].append(i)

for i in range(m):
    info = [int(x) for x in input().split()]
    if info[0]==1:
        weighted[info[1]] = info[-1]
    elif info[0]==2:
        ans = weighted[info[1]]
        dfs(info[1])
        print(ans)

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值