python 基础知识点(蓝桥杯python科目个人复习计划37)

本文详细介绍了深度优先搜索(DFS)中的回溯思想,包括其在求解排列、子集问题以及经典例题如N皇后和小朋友崇拜圈中的应用,通过代码示例展示了如何实现回溯算法并结合剪枝策略优化搜索过程。

今日复习内容:DFS--回溯

1.介绍

回溯:就是DFS是一种,在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

回溯更强调:此路不通,另寻他路,走过的路需要打标记。

回溯法一般在DFS是基础上加上一些剪枝策略

2.个人理解

我理解的回溯,可以用来求排列

排列要求数字不重复,每次选择的数字都需要打标记,记为vis数组

哟输出当前排列,用于记录路径,记为path数组

简单来说,回溯就是先打标记,记录路径,然后下一层,回到上一层,再清除标记的过程。

我现在把它转化成代码:

def dfs(depth):
    # 当前为第depth个数字,0到depth - 1已经设置好
    if depth == n:
        print(path)
        return
    # 枚举第depth个数字
    for i in range(1,n + 1):
        # 数字i必须之前没有选择过
        if vis[i] is False:
            # 标记当前状态
            vis[i] = True
            # 记录当前路径
            path.append(i)
            # 进行下一轮搜索
            dfs(depth + 1)
            # 清空标记
            vis[i] = False
            path.pop(-1)

n = int(input('输入一个整数:'))
path = []
vis = [False] * (n + 1)
dfs(0)

运行结果:

回溯还可以用来求子集

给定n个数字,求子集:(我把它写成代码)

# 和买瓜那个题的思路差不多一样
n = int(input("请输入一个数字:"))
a = list(map(int,input().split()))
path = []
def dfs(depth):
    if depth == n:
        print(path)
        return
    # 该数字被选择的情况下
    path.append(a[depth])
    dfs(depth + 1)
    path.pop(-1)
    # 若是不选
    dfs(depth + 1)

dfs(0)

运行结果:

例题1:N皇后

题目描述:

在N * N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意两个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框呈45度角的斜线上) ,你的任务是:对于给定的N,求出有多少种合法的放置方式。

输入描述:

输入中有一个正整数N <= 10,表示棋盘和皇后的数量。

输出描述:

为一个正整数,表示对应输入行的皇后的不同放置数量。

思路:

dfs枚举每一行放置的列;

标记的内容有:每列只能放一个,主对角线:x + y     副对角线:x - y + n

参考答案:

def dfs(depth):
    if depth == n:
        global ans
        ans += 1
        return
    # 枚举第depth行放在哪列
    for i in range(1,n + 1):
        # 坐标为(depth,i)
        # 第i列先前未选择,主对角线,副对角线都未选择
        if vis1[i] is False and vis2[depth + i] is False and vis3[depth - i + n] is False:
            # 标记当前状态
            vis1[i] = True
            vis2[depth + i] = True
            vis3[depth - i + n] = True
            dfs(depth + 1)
            # 清除标记
            vis1[i] = False
            vis2[depth + i] = False
            vis3[depth - i + n] = False


n = int(input('请输入一个整数:'))
ans = 0
vis1 = [False] * (n  + 1)
vis2 = [False] * (2 * n + 1)
vis3 = [False] * (2 * n + 1)
dfs(0)
print(ans)

运行结果:

例题2:小朋友崇拜圈

题目描述:

班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。

在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。

求满足条件的圈最大多少人?

小朋友编号1,2,3...N

输入描述:

输入第一行,一个整数N(3 < N < 10^5)

接下来一行N个整数,空格分开。

输出描述:

要求输出一个整数,表示满足条件的最大圈的人数。

思路:

depth(x,length):走到x,已经走了length步

参考答案:

import sys
sys.setrecursionlimit(100000)
def dfs(x,length):
    # print(x,length)
    # 记录当前x,已经走了length步
    vis[x] = length
    # 如果下一步已经走过,则说明当前已经形成了一个圈
    if vis[a[x]]:
        # 更新最大圈
        global ans
        ans = max(ans,length - vis[a[x] + 1])

    # 接着走下一步
    else:
        dfs(a[x],length + 1)



n = int(input('请输入一个整数:'))
a = list(map(int,input().split()))
a = [0] + a
vis = [0] * (n + 1)
ans = 0
for i in range(1,n + 1):
    if vis[i] == 0:
        dfs(i,1)
print(ans)

OK,这篇就写到这里 ,下次继续!

ok,这篇就写到这里,下一篇继续!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值