蓝桥杯-深度优先搜索dfs

本文概述了几道2015年至2018年省级竞赛中的编程题目,主要涉及DFS(深度优先搜索)在迷宫、正则表达式、填数、全球变暖和崇拜圈问题中的应用。展示了如何利用DFS解决路径切割、房间遍历和正则匹配等任务,并讨论了剪枝技巧和最优解的求解方法。
摘要由CSDN通过智能技术生成
  1. 2017年省赛-填空题-方格分割-644
'''切割线一定会经过图的中心点,只要确定半条到达
边界的分割线,就能根据这半条对称画出另外半条'''
count = 0
book = [[0]*7 for i in range(7)] #多给一个
next_node = [[-1, 0], [1, 0], [0, -1], [0, 1]]
#按什么顺序应该无所谓吧,也没说字典序啥的
def dfs(x, y):
    global count  #全局变量
    if x == 0 or y == 0 or x == 6 or y == 6:
    # 走到边了,完成分割
        count += 1   
        return
    book[x][y], book[6-x][6-y] = 1, 1
    # 对当前点和当前点的对称点都标记访问
    for i in range(4):
        # 新坐标
        tx = x + next_node[i][0]
        ty = y + next_node[i][1]
        # 如果出界
        if tx < 0 or tx > 6 or ty < 0 or ty > 6:
            continue
        # 没走过,继续往下走
        if book[tx][ty] == 0:
            dfs(tx, ty)
    book[x][y], book[6-x][6-y] = 0, 0
    # 一次dfs结束,取消这个点及其对称点的标记
           
dfs(3,3) # 中心点(3, 3),从(3, 3)出发
print(count//4)
  1. 2017年省赛-填空题-迷宫-641
''' 直接一个一个数也很快。画出通路,通路上的房间都可以出去。'''

maze = ['UDDLUULRUL', 'UURLLLRRRU', 
        'RRUURLDLRD', 'RUDDDDUUUU', 
        'URUDLLRRUU', 'DURLRLDLRL', 
        'ULLURLLRDU', 'RDLULLRDDD',
        'UUDDUDUDLL', 'ULRDLUURRR']
book = [[0]*11 for _ in range(11)]
count = 0

def dfs(x, y):
    global count
    # 走出去了
    if x < 0 or x > 9 or y < 0 or y > 9:
        count += 1
        return
    # 已经走过了
    if book[x][y] == 1: 
        return

    # 对当前点标记访问
    book[x][y] = 1
    if maze[x][y] == 'L':
        dfs(x, y-1)
    if maze[x][y] == 'R':
        dfs(x, y+1)
    if maze[x][y] == 'U':
        dfs(x-1, y)
    if maze[x][y] == 'D':
        dfs(x+1, y)
    book[x][y] = 0
    # 一次dfs结束,取消对当前点的标记

# 对每一个房间(每一个点)进行dfs  
for i in range(10):
    for j in range(10):
        dfs(i, j)
print(count)
  1. 2017年省赛-正则问题-106
'''
((xx|xxx)x|(x|xx))xx
或的两边保留最长的一个x串
每一次dfs()只算一个()内的长度,ans是一个()内x的长度
temp表示从(到|的长度或一整个()内的x长度
'''
s = input()
pos = 0 # 当前位置

def dfs():
    global pos
    temp, ans = 0, 0
    while pos < len(s):
        if s[pos] == '(':
            pos += 1
            temp += dfs()
        elif s[pos] == 'x':
            pos += 1
            temp += 1
        elif s[pos] == '|':
            pos += 1
            ans = max(ans, temp)
            temp = 0
        elif s[pos] == ')':
            pos += 1
            ans = max(ans, temp)
            return ans
    ans = max(ans, temp)
    return ans

print(dfs())
  1. 2016年省赛-填空题-寒假作业-1388
    剪枝,不用生成一个完整的排列。需要自写全排列。
ans = 0
l = [0 for _ in range(15)]
# 用来存放每一次的13个数,l[0]空置
book = [0 for _ in range(15)]

def check3():
# 检查前三个数是否符合等式
    return l[1] + l[2] == l[3]
def check6():
    return l[4] - l[5] == l[6]
def check9():
    return l[7] * l[8] == l[9]
def check12():
    return l[10] / l[11] == l[12]

def dfs(num):
    global ans
    if num == 13:
        if check12():
            ans += 1
        return
    if num == 4 and not check3():
        return
    if num == 7 and not check6():
        return
    if num == 10 and not check9():
        return
    for i in range(1, 14):
        if book[i] == 0: # 未被访问
            l[num] = i
            book[i] = 1 # 标记访问
            dfs(num+1)
            book[i] = 0

dfs(1) # 从第一个方块开始
print(ans)

类似的题目:方格填数-664,但是这一题用dfs也很烦,还不如用全排列暴力求解。

  1. 2018年省赛-全球变暖-178
    这一题也可以用bfs做
    还是有一个测试用例不能通过😢
import sys
sys.setrecursionlimit(int(1e4))
N = int(input())
ph = []
for i in range(N):
    ph.append(input())
    assert len(ph[-1]) == N
book = [[0]*N for _ in range(N)]
next_node = [[-1, 0], [1, 0], [0, 1], [0, -1]]
count = 0

def dfs(x, y):
    global flag
    book[x][y] = 1
    if ph[x+1][y] == '#' and ph[x-1][y] == '#' and ph[x][y+1] == '#' and ph[x][y-1] == '#':
        flag = 1
    for i in range(4):
        tx = x + next_node[i][0]
        ty = y + next_node[i][1]
        # 把周围所有#都标记上flag
        if book[tx][ty] == 0 and ph[tx][ty] == '#':
            dfs(tx, ty)

for i in range(N):
    for j in range(N):
        if ph[i][j] == '#' and book[i][j] == 0: #对符合这个条件的所有点dfs
            flag = 0
            dfs(i, j)
            if flag == 0:
                count += 1

print(count)
  1. 2015年国赛-填空题-四阶幻方-689
    和寒假作业简直一模一样。需要不断地剪枝,剪枝,剪枝。
    每行每列每条对角线之和应当是34.
    (1+16+8+9 = 2+15+8+9 = … = 34)
ans = 0
l = [0 for _ in range(17)]
l[1] = 1
book = [0 for _ in range(17)]
book[1] = 1

def check4():
    return 1 + l[2] + l[3] + l[4] == 34
def check8():
    return l[5] + l[6] + l[7] + l[8] == 34
def check12():
    return l[9] + l[10] + l[11] + l[12] == 34
def check13():
    return 1 + l[5] + l[9] + l[13] == 34 and l[4] + l[7] + l[10] + l[13] == 34
def check14():
    return l[2] + l[6] + l[10] + l[14] == 34
def check15():
    return l[3] + l[7] + l[11] + l[15] == 34
def check16():
    return l[13] + l[14] + l[15] + l[16] == 34 and l[4] + l[8] + l[12] + l[16] == 34 and 1 + l[6] + l[11] + l[16] == 34

def dfs(num):
    global ans
    if num == 17:
        if check16():
            ans += 1
            return
    if num == 5 and not check4():
        return
    if num == 9 and not check8():
        return
    if num == 13 and not check12():
        return
    if num == 14 and not check13():
        return
    if num == 15 and not check14():
        return
    if num == 16 and not check15():
        return
    for i in range(2, 17):
        if book[i] == 0:
            l[num] = i
            book[i] = 1
            dfs(num+1)
            book[i] = 0

dfs(2)
print(ans)
  1. 2016年省赛-四平方和-122
    暴力法:
import math
n = int(input())
# 创建一个平方列表
w = int(math.sqrt(n)) + 1
l = [i ** 2 for i in range(w)]

def fun(m):
    for i in range(m):
        if n < i ** 2:
            continue
        for j in range(i, m):
            if n < i ** 2 + j ** 2:
                continue
            for k in range(j, m):
                z = n - (i ** 2 + j ** 2 + k ** 2)
                if z < 0:
                    continue
                if z in l:
                    st = sorted([i, j, k, int(math.sqrt(z))])
                    return st[0], st[1], st[2], st[3]

a, b, c, d = fun(w)
print(a, b, c, d)

dfs代码:

import math
import sys
n = int(input())
l = [0] * 4
def dfs(num, rst, las):
    m = int(math.sqrt(rst))
    flag = 0
    if num > 2:
        if m >= las and m ** 2 == rst:
            print(l[0], l[1], l[2], m)
            sys.exit()
        return
    for i in range(las, m+1):
        l[num] = i
        dfs(num+1, rst-i*i, i)

dfs(0, n, 0)
  1. 2018年省赛-小朋友崇拜圈-182
import sys
#防止无限递归导致 Python 崩溃
sys.setrecursionlimit(int(1e6))
n = int(input())
ls = [0] + list(map(int, input().split()))
book = [0] * (n+1)
ans = 0

def dfs(x, y):
    global ans
    #终止条件:被访问过
    if book[x]:
        ans = max(ans, y-book[x]) # 终止值-起始值
        return
    book[x] = y
    dfs(ls[x], y+1)

for i in range(1, n+1):
    if not book[i]:
        dfs(i, 1)

print(ans)

python标准库-sys

  1. 水管工游戏
n, m = map(int, input().split()) # n行m列
mp = []
for i in range(n):
    mp.append(list(map(int, input().split())))
assert len(mp) == n
drct = [[1, 0], [-1, 0], [0, 1], [0, -1]] # 出水管在上下左右
book = [[0]*m for _ in range(n)]
flag = 0
s = []
def dfs(x, y, fr):
    global flag, s
    if x== n-1 and y == m:
        flag = 1
        for i in range(len(s)):
            print("({},{})".format(s[i][0]+1, s[i][1]+1), end=' ')
        return
    if x < 0 or x >= n or y < 0 or y >= m:
        return
    if book[x][y] == 1:
        return
    book[x][y] = 1

    # 入栈
    s.append([x, y])
    # 直管
    if mp[x][y] == 5 or mp[x][y] == 6:
        dfs(x+drct[fr][0], y+drct[fr][1], fr)
    # 弯管
    if 1 <= mp[x][y] <= 4:
        if fr == 0 or fr == 1: # 进水口在上/下面
            dfs(x, y+1, 2)
            dfs(x, y-1, 3)
        if fr == 2 or fr == 3:
            dfs(x+1, y, 0)
            dfs(x-1, y, 1)
    
    book[x][y] = 0
    s = s[:-1] # 出栈
    return

dfs(0, 0, 2)
if flag == 0:
    print("impossible")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值