DFS算法及应用(二)

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

DFS算法及应用(一)+https://developer.aliyun.com/article/1544412?spm=a2c6h.13148508.setting.19.1fa24f0eaie4S4



回溯


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


回溯强调走过的路要打标记,一搬在DFS基础上加一些剪枝策略。


回溯模板求排列



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


  • 每次成功时打印path路径。


  • 打标记,记路径,然后下一层,回到上一层,清除标记。


def dfs(depth):
    # 第几个数字
    if depth == n:   # 以前还需要判断,但是通过回溯,直接打印就行了
        print(path)
        return
 
    # 第depth个数字可以选择下边的数
    for i in range(1, n + 1):
        if vis[i]:
            continue
        vis[i] = True
        path.append(i)
        dfs(depth + 1)
        vis[i] = False    # 返回到上一个,即返回到最后一层,因为的depth+1是溢出的一层了
        path.pop(-1)
 
 
# 选择的数字必须未标记
 
 
n = int(input())
vis = [False] * (n + 1)  # 如果是3个数,就是:[][][][] 0这个数不在排列内(索引代表数字)
path = []
dfs(0)


VIS数组的索引代表这个数字,值代表这个数有没有被选取,每次通过for循环选择数字,如果该数之前没有,则将其标记并append到path路径中,最后在dfs下边写出回退时的操作(去除标记、弹出path)


回溯模板求子集



  • 给定n个数字,求子集。


  • 可以针对每个数字,做出选择:选不选。


def dfs(depth):
    if depth == n:
        print(path)
        return
    # 选
    path.append(a[depth])
    dfs(depth + 1)
    path.pop(-1)  # 执行完递归后依次在此逐个倒退执行
    # 不选
    dfs(depth + 1)
 
 
n = int(input())
a = list(map(int, input().split()))
path = []
 
 
dfs(0)


崇拜圈


班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。求满足条件的圈最大多少人?

输入第一行,一个整数N(3



def dfs(x, length):
    # 记录走到x的步长
    vis[x] = length
 
    # 判断下一个点是否走过
    if vis[a[x]] != 0:
        global ans
        ans = max(ans, length - vis[a[x]] + 1)
    else:
        dfs(a[x], length + 1)
 
 
n = int(input())
a = [0] + list(map(int, input().split()))
# 标记数组,vis[x]代表点X的步数
vis = [0] * (n + 1)
ans = 0
for i in range(1, n + 1):
    if vis[i] == 0:
        dfs(i, 1)
print(ans)


a列表代表的索引为i的小朋友崇拜的人是几号,同样用vis代表索引为i的小朋友走几步才到。


剪枝


  • 在搜索过程中,如果需要完全遍历所有情况可能需要很多时间。


  • 在搜索到某种状态时,根据当前状态判断出后续无解,则该状态无需继续深入搜索。


  • 例如:给定N个正整数,求出有多少个子集之和小于等于K。在搜索过程中当前选择的数字和已经超过K则不需要继续搜索。


数字排队


数字王国开学了,它们也和我们人类一样有开学前的军训,现在一共有n名学生,每个学生有自己的一个名字a(数字王国里的名字就是一个正整数,注意学生们可能出现重名的情况),此时叛逆教官来看了之后感觉十分别扭,决定将学生重新分队。排队规则为:将学生分成若干队,每队里面至少—个学生,且每队里面学生的名字不能出现倍数关系(注意名字相同也算是倍数关系)。现在请你帮忙算算最少可以分成几队?


例:有4名学生(2,3,4,4),最少可以分成(2,3)、(4)、(4)共3队。


输入格式:


第一行包含一个正整数n,表示学生数量。


第二行包含n个由空格隔开的整数,第i个整数表示第i个学生的名字a。


def check(x, group):
    for y in group:
        if x % y == 0 or y % x == 0:
            return False
    return True
 
 
def dfs(depth):
    # 最优性剪枝
    global ans
    if len(Groups) > ans:
        return
    if depth == n:
        global ans
        ans = min(ans, len(Groups))
        return
 
    # 对于每个学生,枚举该学生放在哪一组
    # 看看当前学生能否加到这一组
    for every_group in Groups:
        if check(a[depth], every_group):
            every_group.append(a[depth])
            dfs(depth + 1)
            every_group.pop()
 
    # 对于每个学生也可以单独作为一组
    Groups.append([a[depth]])
    dfs(depth + 1)
    Groups.pop()
 
 
n = int(input())
a = list(map(int, input().split()))
# Groups是二维数组,每个组的情况
Groups = []  # 构建一个初始的数组和初始的答案
ans = n
dfs(0)
print(ans)



N边形


假设一个n边形n条边为a1,a2,a3,…- ,an,定义该n边形的值u=ax ag x a3x··× an。


定义两个n边形不同是指至少有—条边的长度在一个n边形中有使用而另一个n边形没有用到,如n边形(3,4,5,6)和(3,5,4,6)是两个相同的n边形,(3,4,5,6)和(4,5,6,7)是两个不相同的n边形。现在有t和n,表示t个询问并且询问的是n边形,每个询问给定一个区间[l,7],问有多少个n边形(要求该n边形自己的n条边的长度互不相同)的值在该区间范围内。


输入格式:


第—行包含两个正整数t、n,表示有t个询问,询问的是n边形。


接下来t行,每行有两个空格隔开的正整数l、r,表示询问区间[l,r]。


# 利用DFS求所有的N边形
# N边形:最小的N-1条边之和大于第N边  等价于  N边之和 > 2 * 第N边
def dfs(depth, last_val, tot, mul):
    # depth表示第几条边
    # last_val是上一条边长
    # 当前所有边长之和
    if depth == n:
        if tot > 2 * path[-1]:  # 因为每条边递增
            ans[mul] += 1
        return
 
    # 枚举第depth条边的边长
    for i in range(last_val + 1, 100000):
        # 剪枝保证当前乘积不超过100000
        if mul * (i ** (n - depth)) <= 100000:
            path.append(i)
            dfs(depth + 1, i + 1, tot + i, mul * i)
            path.pop()
        else:
            break
 
 
ans = [] * 1000001
t, n = map(int, input().split())
path = []
dfs(0, 0, 0, 1)
# 每次询问一个区间[l,r],输出有多少个N边形的价值在区间中
# 等价于ans[l]+...+ans[r]
for i in range(100001):
    ans[i] += ans[i - 1]  # 求前缀和
for _ in range(t):
    l, r = map(int, input().split())
    print(ans[r] - ans[l-1])


相关文章
|
6月前
|
机器学习/深度学习 算法 C++
【DFS/回溯算法】2016年蓝桥杯真题之路径之谜详解
题目要求根据城堡北墙和西墙箭靶上的箭数,推断骑士从西北角到东南角的唯一路径。每步移动时向正北和正西各射一箭,同一格不重复经过。通过DFS回溯模拟“拔箭”过程,验证路径合法性。已知箭数约束路径唯一,最终按编号输出行走顺序。
|
8月前
|
存储 监控 JavaScript
基于布隆过滤器的 Node.js 算法在局域网电脑桌面监控设备快速校验中的应用研究
本文探讨了布隆过滤器在局域网电脑桌面监控中的应用,分析其高效空间利用率、快速查询性能及动态扩容优势,并设计了基于MAC地址的校验模型,提供Node.js实现代码,适用于设备准入控制与重复数据过滤场景。
305 0
|
7月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
423 3
|
7月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
|
7月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
380 3
|
7月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
7月前
|
机器学习/深度学习 算法 安全
小场景大市场:猫狗识别算法在宠物智能设备中的应用
将猫狗识别算法应用于宠物智能设备,是AIoT领域的重要垂直场景。本文从核心技术、应用场景、挑战与趋势四个方面,全面解析这一融合算法、硬件与用户体验的系统工程。
670 0
|
9月前
|
机器学习/深度学习 人工智能 算法
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
AI-Compass 强化学习模块:理论到实战完整RL技术生态,涵盖10+主流框架、多智能体算法、游戏AI与金融量化应用
|
8月前
|
算法 数据可视化
matlab版本粒子群算法(PSO)在路径规划中的应用
matlab版本粒子群算法(PSO)在路径规划中的应用
|
9月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
200 0

热门文章

最新文章