当前位置: 首页 > article >正文

蓝桥杯 之 暴力回溯

文章目录

  • 数字接龙
  • 小u的最大连续移动次数问题
  • 迷宫

  • 在蓝桥杯中,十分喜欢考察对于网格的回溯的问题,对于这类的问题,常常会使用到这个DFSBFS进行考察,不过无论怎么考察,都只是会在最基础的模本的基础上,根据这个题目的条件:
    • 增加递归传递的参数
    • 增加条件转移的时候的条件的判断
    • 考察对于终止状态的设置,答案的存储与更新

数字接龙

数字接龙

在这里插入图片描述
在这里插入图片描述

  • 查看数据范围,适合直接进行暴露的DFS搜索
  • 题目的条件有点多,我们逐一进行分析:
    • 需要记录哪些信息?
      • 当前位置的数字,当前的坐标,当前访问过的方格的数目
      • 为了保证每一个格子只能访问过一次,所以得使用visited数组
      • 移动的方向的,得使用一个二维数组step来记录,得逐一步伐的顺序与对应的方位顺序是一致的
      • 对于答案的记录,考虑使用这个字符来记录,最后再合并就好了
      • 对于交叉的判断的综合考虑?

代码版本1,不考虑这个交叉的问题

import os
import sys

# sys.setrecursionlimit(10 ** 6)
# 请在此输入您的代码

N,K = map(int,input().split())
e = []
# 存储图
for _ in range(N):
  tmp = list(map(int,input().split()))
  e.append(tmp)

# 状态转移的路径,左,右,上,下,左上角,右上角,左下角,右下角
# 转移还得按照这个顺序
#step = [[0,-1],[0,1],[-1,0],[1,0],[-1,-1],[-1,1],[1,-1],[1,1]]
step = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]

ans = []
path = []

visited = [[False]*N for _ in range(N)]

# 开始深度搜索,每一步的时候,判断下面是否是0,还是i+1,还得判断是否都走过了每一个位置
def dfs(i,x,y,cursum):
  # 终止状态
  if x == N-1 and y == N-1 and cursum == N*N:
    ans.append(int(''.join(path)))

  # 如何转移?
  for j in range(8):
    nx,ny = x+step[j][0],y+step[j][1]
    if 0<= nx < N and 0<= ny < N and not visited[nx][ny] and (e[nx][ny] == 0 or e[nx][ny] == i + 1):
      # 还是得存储这个字符形式
      visited[nx][ny] = True
      path.append(str(j))
      dfs(e[nx][ny],nx,ny,cursum+1)
      path.pop()
      visited[nx][ny] = False

visited[0][0] = True
dfs(e[0][0],0,0,1)
if ans:
  print(min(ans))
else:
  print(-1)

  • 测试样例的通过的情况:

在这里插入图片描述
在这里插入图片描述

增加了对于交叉的判断


import os
import sys

# sys.setrecursionlimit(10 ** 6)
# 请在此输入您的代码

N,K = map(int,input().split())
e = []
# 存储图
for _ in range(N):
  tmp = list(map(int,input().split()))
  e.append(tmp)

# 状态转移的路径,左,右,上,下,左上角,右上角,左下角,右下角
# 转移还得按照这个顺序
#step = [[0,-1],[0,1],[-1,0],[1,0],[-1,-1],[-1,1],[1,-1],[1,1]]
step = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]

ans = []
path = []

visited = [[False]*N for _ in range(N)]

# 开始深度搜索,每一步的时候,判断下面是否是0,还是i+1,还得判断是否都走过了每一个位置
def dfs(i,x,y,cursum):
  # 终止状态
  if x == N-1 and y == N-1 and cursum == N*N:
    ans.append(int(''.join(path)))

  # 如何转移?
  for j in range(8):
    nx,ny = x+step[j][0],y+step[j][1]
    if 0<= nx < N and 0<= ny < N and not visited[nx][ny] and (e[nx][ny] == 0 or e[nx][ny] == i + 1):
      if j == 1 and 0<= x-1 and y+1 < N:
        if visited[x][y+1] and visited[x-1][y]:
          continue
      if j == 3 and x+1 < N and y+1 < N:
        if visited[x][y+1] and visited[x+1][y]:
          continue
      if j == 5 and x+1 < N and 0<= y-1:
        if visited[x][y-1] and visited[x+1][y]:
          continue
      if j == 7 and 0<= y-1 and 0<= x-1:
        if visited[x][y-1] and visited[x-1][y]:
          continue

      # 还是得存储这个字符形式
      visited[nx][ny] = True
      path.append(str(j))
      dfs(e[nx][ny],nx,ny,cursum+1)
      path.pop()
      visited[nx][ny] = False

visited[0][0] = True
dfs(e[0][0],0,0,1)
if ans:
  print(min(ans))
else:
  print(-1)
  • 样例通过情况

在这里插入图片描述
在这里插入图片描述

  • 改进这个交叉判断,上面的判断其实是不合理的,因为如果左右两边的位置都被访问过的话,并不确定对应的对角线是存在线的,正确的做法就是使用多一个数组记录当前位置的下一步是什么,如果左右位置存在对角线,那么就不能通过

import os
import sys

# sys.setrecursionlimit(10 ** 6)
# 请在此输入您的代码

N,K = map(int,input().split())
e = []
# 存储图
for _ in range(N):
  tmp = list(map(int,input().split()))
  e.append(tmp)

# 状态转移的路径,左,右,上,下,左上角,右上角,左下角,右下角
# 转移还得按照这个顺序
#step = [[0,-1],[0,1],[-1,0],[1,0],[-1,-1],[-1,1],[1,-1],[1,1]]
step = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]

ans = []
path = []

visited = [[False]*N for _ in range(N)]
nextstep = [[-1]*N for _ in range(N)]


# 开始深度搜索,每一步的时候,判断下面是否是0,还是i+1,还得判断是否都走过了每一个位置
def dfs(i,x,y,cursum):
  # 终止状态
  if x == N-1 and y == N-1 and cursum == N*N:
    if not ans:
      ans.append(int(''.join(path)))
    return 
  # 如何转移?
  for j in range(8):
    nx,ny = x+step[j][0],y+step[j][1]
    if 0<= nx < N and 0<= ny < N and not visited[nx][ny] and (e[nx][ny] == 0 or e[nx][ny] == i + 1):
      if j == 1 and (nextstep[nx][ny-1] == 3 or nextstep[nx-1][ny] == 7): continue
      if j == 3 and (nextstep[nx-1][ny] == 5 or nextstep[nx][ny-1] == 1): continue
      if j == 5 and (nextstep[nx-1][ny] == 3 or nextstep[nx][ny+1] == 7): continue
      if j == 7 and (nextstep[nx+1][ny] == 1 or nextstep[nx][ny+1] == 5): continue
      nextstep[x][y] = j
      # 还是得存储这个字符形式
      visited[nx][ny] = True
      path.append(str(j))
      dfs(e[nx][ny],nx,ny,cursum+1)
      if ans:
        return 
      path.pop()
      visited[nx][ny] = False
      nextstep[x][y] = -1

visited[0][0] = True
dfs(e[0][0],0,0,1)
if ans:
  print(min(ans))
else:
  print(-1)

小u的最大连续移动次数问题

小u的最大连续移动次数问题

在这里插入图片描述

  • 直接暴力进行求解
  • 这个问题的难点在于这个没有明确的终止状态,所以考虑使用一个全局的变量进行动态的更新,直接都不返回值
  • 需要记录的信息:
    • 当前的位置x,y,当前的步数step,上一个状态是上坡还是下坡flag
def solution(m: int, n: int, a: list) -> int:
    # 先写一个dfs模版,后面再每一个点都进行调用
    sstep = [[0,-1],[0,1],[-1,0],[1,0]]
    visited = [[False]*n for _ in range(m)]
    ans = 0
    # 还得增加一个变量记录上次是上坡还是下坡,flag = 1表示上,-1表示下
    def dfs(x,y,step,flag):
        nonlocal ans
        ans = max(ans,step)
        for s in sstep:
            nx,ny = x+s[0],y+s[1]
            if 0<= nx < m and 0<= ny < n and not visited[nx][ny]:
                if flag == -1 and a[nx][ny] > a[x][y]:
                    visited[nx][ny] = True
                    dfs(nx,ny,step+1,1)
                    visited[nx][ny] = False
                if flag == 1 and a[nx][ny] < a[x][y]:
                    visited[nx][ny] = True
                    dfs(nx,ny,step+1,-1)
                    visited[nx][ny] = False
    ans = 0
    for i in range(m):
        for j in range(n):
            visited[i][j] = True
            dfs(i,j,0,1)
            dfs(i,j,0,-1)
            visited[i][j] = False
    return ans

迷宫

迷宫

在这里插入图片描述

在这里插入图片描述

  • 求解的是最短距离的问题,所以首先得想到使用这个BFS进行求解
  • 由于求解的是随机起点到终点的距离,所以我们直接逆向思考,直接从终点进行遍历,当栈为空的时候,就说明已经遍历完全部的位置了

from collections import deque, defaultdict

n, m = map(int, input().split())
change = defaultdict(list)
for _ in range(m):
    x1, y1, x2, y2 = map(int, input().split())
    x1, y1, x2, y2 = x1 - 1, y1 - 1, x2 - 1, y2 - 1
    change[(x1, y1)].append((x2, y2))
    change[(x2, y2)].append((x1, y1))

def bfs(start, end):
    queue = deque([(start, end)])
    visited = [[-1] * n for _ in range(n)]  # 使用二维数组记录步数,初始值为 -1
    visited[start][end] = 0
    step = [[0, -1], [0, 1], [-1, 0], [1, 0]]
    while queue:
        s, e = queue.popleft()
        # 访问邻居
        for dx, dy in step:
            nx, ny = s + dx, e + dy
            if 0 <= nx < n and 0 <= ny < n and visited[nx][ny] == -1:
                visited[nx][ny] = visited[s][e] + 1
                queue.append((nx, ny))
        # 走传送门
        if (s, e) in change:
            for nx, ny in change[(s, e)]:
                if visited[nx][ny] == -1:
                    visited[nx][ny] = visited[s][e] + 1
                    queue.append((nx, ny))
    # 计算平均步数
    total = 0
    for x in range(n):
        for y in range(n):
          total += visited[x][y]
    return total / (n * n)

print(f"{bfs(n - 1, n - 1):.2f}")

http://www.kler.cn/a/595474.html

相关文章:

  • 3.16[A]FPGA
  • Pytest基础使用
  • Netty源码—3.Reactor线程模型三
  • L2TP实验报告
  • 无服务器架构将淘汰运维?2025年云计算形态预测
  • RabbitMQ 与 Kafka:消息中间件的终极对比与选型指南
  • MSE分类时梯度消失的问题详解和交叉熵损失的梯度推导
  • Redis哨兵模式(Sentinel)高可用方案介绍与配置实践
  • 数字孪生技术引领UI前端设计新风尚:跨平台与响应式设计的结合
  • 【Bluebell】项目总结:基于 golang 的前后端分离 web 项目实战
  • ue5蓝图项目转换为c++项目 遇到的问题
  • VectorBT:Python量化交易策略开发与回测评估详解
  • 如何缓解大语言模型推理中的“幻觉”(Hallucination)?
  • deepSpeed多机多卡训练服务器之间,和服务器内两个GPU是怎么通信
  • 识别并脱敏上传到deepseek/chatgpt的文本文件中的身份证/手机号
  • 单片机自学总结
  • 架构设计之自定义延迟双删缓存注解(上)
  • 【C++基础】Lambda 函数 基础知识讲解学习及难点解析
  • vscode连接本地mysql数据库
  • 解决python配置文件类configparser.ConfigParser,插入、读取数据,自动转为小写的问题