DFS——连通性和搜索顺序(回溯)

news2025/2/3 7:03:27

文章目录

        • 概述
        • 连通性问题
          • 模板
          • 思考
          • 迷宫
          • 红与黑
        • 搜索顺序(回溯)
          • 模板
          • 思考
          • 马走日
          • 单词接龙
          • 分成互质组
        • 总结

概述

  1. 定义
    在深度优先搜索中,对于最新发现的顶点,如果它还有以此为顶点而未探测到的边,就沿此边继续探测下去,当顶点v的所有边都已被探寻过后,搜索将回溯到发现顶点v有起始点的那些边。这一过程一直进行到已发现从源顶点可达的所有顶点为止。如果还存在未被发现的顶点,则选择其中一个作为源顶点,并重复上述过程。整个过程反复进行,直到所有的顶点都被发现时为止。
  2. 分类
    内部dfs:一般为连通性问题,整个图作为一个状态。只需要把图中每个点都遍历到,记录其存在或者一些性质的状态即可。
    在这里插入图片描述

外部dfs:一般求方案数量和最值,搜索顺序的不同状态也不同,应带有回溯。
在这里插入图片描述

连通性问题

模板
def dfs(u) :
	if (障碍终止条件\优化终止条件) : return ..
	if (终点终止条件) : return ..
	st[u] = True #标记已经遍历过
	for i in range(...) : #选择路径
		t = u + path[i]
		if 边界条件 : continue
		if st[t] : continue
		dfs(t)	
思考

连通性问题实质上是存在性问题,一般可以求解是否存在连通块与存在连通块的个数

迷宫

一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n 的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。

同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。

如果起点或者终点有一个不能通行(为#),则看成无法办到。

注意:A、B不一定是两个不同的点。

输入格式
第1行是测试数据的组数 k,后面跟着 k 组输入。

每组测试数据的第1行是一个正整数 n,表示迷宫的规模是 n∗n 的。

接下来是一个 n∗n 的矩阵,矩阵中的元素为.或者#。

再接下来一行是 4 个整数 ha,la,hb,lb,描述 A 处在第 ha 行, 第 la 列,B 处在第 hb 行, 第 lb 列。

注意到 ha,la,hb,lb 全部是从 0 开始计数的。

输出格式
k行,每行输出对应一个输入。

能办到则输出“YES”,否则输出“NO”。

数据范围
1≤n≤100
输入样例:
2
3
.##
…#
#…
0 0 2 2
5

###.#
…#…
###…
…#.
0 0 4 0
输出样例:
YES
NO

import sys
sys.setrecursionlimit(110 * 110)

T = int(input())

DIRC = [[-1, 0], [0, 1], [1, 0], [0, -1]]

def dfs(sx, sy, ex, ey) :
	if g[sx][sy] == '#' :#障碍终止条件
		return False
	if sx == ex and sy == ey : return True #终点终止条件
	st[sx][sy] = True #标记状态
	for i in range(4) : #遍历路径
		a, b = sx + DIRC[i][0], sy + DIRC[i][1]
		if a < 0 or a >= n or b < 0 or b >= n : continue # 越界筛查
		if st[a][b] : continue #去重
		if dfs(a, b, ex, ey) : return True #存在通路则返回True
	return False #没有通路返回False

for t in range(T) :
	n = int(input())
	g = []
	for i in range(n) :
		g.append(input())
	sx, sy, ex, ey = map(int, input().split())
	st = [[False] * n for _ in range(n)]
	if dfs(sx, sy, ex, ey) : print("YES")
	else : print("NO")
红与黑

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。

你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。

请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

输入格式
输入包括多个数据集合。

每个数据集合的第一行是两个整数 W 和 H,分别表示 x 方向和 y 方向瓷砖的数量。

在接下来的 H 行中,每行包括 W 个字符。每个字符表示一块瓷砖的颜色,规则如下

1)‘.’:黑色的瓷砖;
2)‘#’:红色的瓷砖;
3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。

当在一行中读入的是两个零时,表示输入结束。

输出格式
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。

数据范围
1≤W,H≤20
输入样例:
6 9
…#.
…#





#@…#
.#…#.
0 0
输出样例:
45

DIRC = [[-1, 0], [0, 1], [1, 0], [0, -1]]

def dfs(x, y) :
	if g[x][y] == '#' : return 0 #障碍终止条件
	
	cnt = 1 #(x, y)基点的计数
	st[x][y] = True
	for i in range(4) :
		a, b = x + DIRC[i][0], y + DIRC[i][1]
		if a < 0 or a >= n or b < 0 or b >= m : continue
		if st[a][b] : continue
		cnt += dfs(a, b)
	return cnt

while True :
	m, n = map(int, input().split())
	if m == 0 and n == 0 : break
	g = []
	for i in range(n) :
		g.append(input())
	
	st = [[False] * m for _ in range(n)]
	for i in range(n) :
		for j in range(m) :
			if g[i][j] == '@' :
				print(dfs(i, j))
				break

搜索顺序(回溯)

模板

考虑搜索顺序,就是回溯,要做到不重不漏

dfs(u) :
	if 终止条件 : return...
	#如果此层不会使用u则可在这里对树枝去重st[u] = True
	for i in path :
		if check(u, i) :#检查状态是否合法
			st[i] = True #树枝去重
			dfs(u + i)
			st[i] = False #恢复现场			
思考

dfs回溯难点在于状态的保存
这里面有些技巧:
1、在回溯前预处理,首尾关系记录两两状态关系
2、对于状态的每个性质,分开存储
dfs的参数必须能够表示或者求出当前状态,这里的状态与终止条件与路径选择合法性有关
排列问题路径选择都是从头开始查找到没被遍历的节点
组合问题路径需要在上一层的基础上查找没有遍历的点

马走日

马在中国象棋以日字形规则移动。

请编写一段程序,给定 n∗m 大小的棋盘,以及马的初始位置 (x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

输入格式
第一行为整数 T,表示测试数据组数。

每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标 n,m,x,y。

输出格式
每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,若无法遍历棋盘上的所有点则输出 0。

数据范围
1≤T≤9,
1≤m,n≤9,
1≤n×m≤28,
0≤x≤n−1,
0≤y≤m−1
输入样例:
1
5 4 0 0
输出样例:
32

T = int(input())
DIRC = [[-2, -1], [-2, 1], [-1, 2], [1, 2], [2, 1], [2, -1], [1, -2], [-1, -2]]

def dfs(x, y, cnt) :
	global ans
	if cnt == n * m : # 终点条件
		ans += 1
		return
	st[x][y] = True
	for i in range(8) : #路径选择
		a, b = x + DIRC[i][0], y + DIRC[i][1]
		if a < 0 or a >= n or b < 0 or b >= m : continue
		if st[a][b] : continue 
		dfs(a, b)
	st[x][y] = False

for t in range(T) :
	n, m, sx, sy = map(int, input().split())
	st = [[False] * m for _ in range(n)]
	ans = 0
	dfs(sx, sy, 1)
	print(ans)

这里cnt对应于终止条件,路径选择只需要保证合法性和树枝去重即可

单词接龙

单词接龙是一个与我们经常玩的成语接龙相类似的游戏。

现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”,每个单词最多被使用两次。

在两个单词相连时,其重合部分合为一部分,例如 beast 和 astonish ,如果接成一条龙则变为 beastonish。

我们可以任意选择重合部分的长度,但其长度必须大于等于1,且严格小于两个串的长度,例如 at 和 atide 间不能相连。

输入格式
输入的第一行为一个单独的整数 n 表示单词数,以下 n 行每行有一个单词(只含有大写或小写字母,长度不超过20),输入的最后一行为一个单个字符,表示“龙”开头的字母。

你可以假定以此字母开头的“龙”一定存在。

输出格式
只需输出以此字母开头的最长的“龙”的长度。

数据范围
n≤20,
单词随机生成。

输入样例:
5
at
touch
cheat
choose
tact
a
输出样例:
23
提示
连成的“龙”为 atoucheatactactouchoose。

N = 25

p = []
g = [[0] * N for _ in range(N)]
used = [0] * N
ans = 0

def dfs(dragon, last) : #last参数是为了判断路径选择的合法性和树枝去重
	global ans
	ans = max(ans, len(dragon))
	used[last] += 1
	for i in range(n) :
		if used[i] < 2 and g[last][i] :
			dfs(dragon + p[i][g[last][i] :], i)
	used[last] -= 1

n = int(input())
for i in range(n) :
	p.append(input())
st = input()
for i in range(n) :
	for j in range(n) :
		a, b = p[i], p[j]
		for k in range(1, min(len(a), len(b))) :
			if a[-k :] == b[:k] :
				g[i][j] = k
				break
for i in range(n) :
	if p[i][0] == st :
		dfs(p[i], i)
print(ans)
分成互质组

给定 n 个正整数,将它们分组,使得每组中任意两个数互质。

至少要分成多少个组?

输入格式
第一行是一个正整数 n。

第二行是 n 个不大于10000的正整数。

输出格式
一个正整数,即最少需要的组数。

数据范围
1≤n≤10
输入样例:
6
14 20 33 117 143 175
输出样例:
3

N = 15

st = [False] * N
group = [[0] * N for _ in range(N)]
ans = N

def gcd(a, b) : #
	return a if b == 0 else gcd(b, a % b)

def check(group, gc, i) : #判断i与group数组中所有元素是否互质
	for j in range(gc) :
		if gcd(p[group[j]], p[i]) > 1 :
			return False
	return True

def dfs(g, gc, ct, start) :
	global ans
	if g >= ans : return # 优化剪枝
	if ct == n : ans = g # 终点终止条件
	
	flag = True #判断是否可能被划分到g组
	for i in range(start, n) :
		if not st[i] and check(group[g], gc, i) :
			st[i] = True
			group[g][gc] = i
			dfs(g, gc + 1, ct + 1, i + 1)
			group[g][gc] = 0
			st[i] = False
			flag = False
	if flag : dfs(g + 1, 0, ct, 0) #开一个新组
	
n = int(input())
p = list(map(int, input().split()))
dfs(1, 0, 0, 0)
print(ans)

在这里插入图片描述

总结

dfs分为连通(内部)dfs和回溯(外部)dfs,回溯dfs的枚举又分为枚举排列和组合类型的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript刷LeetCode拿offer-滑动窗口

一、前言 《JavaScript刷LeetCode拿offer-双指针技巧》中&#xff0c;简单地介绍了双指针技巧相比较单指针的优点&#xff0c;以及结合 Easy 难度的题目带大家进一步了解双指针的应用。 进入 Medium 难度之后&#xff0c;解题的关键在于如何构造双指针以及确定指针移动的规则…

从 0 开始学 Python 自动化测试开发(二):环境搭建

本文是「从 0 开始学 Python 自动化测试开发」专题系列文章第二篇 —— 环境搭建篇&#xff0c;适合零基础入门的同学。没有阅读过上一篇的同学&#xff0c;请戳主页看上一篇噢。作者方程老师&#xff0c;是前某跨国通信公司高级测试经理&#xff0c;目前为某互联网名企资深测试…

常见管理网络的net命令

目录1 简介2 常用命令2.1 net view2.2 net user2.3 net use2.4 net start2.5 net stop2.6 net share1 简介 net 命令是一种基于网络的命令&#xff0c;该命令包含了管理网络环境、服务、用户、登录等大部分重要的管理功能。 2 常用命令 2.1 net view 作用&#xff1a;显示域…

Spring 之 @Component 和 @Configuration 两者区别以及源码分析

之前一直搞不清 Component 和 Configuration 这两个注解到底有啥区别&#xff0c;一直认为被这两修饰的类可以被 Spring 实例化嘛&#xff0c;不&#xff0c;还是见识太短&#xff0c;直到今天才发现这两玩意有这么大区别。很幸运能够及时发现&#xff0c;后面可以少走点坑&…

操作系统知识点

操作系统的目标&#xff1a; 方便&#xff1a;使计算机系统易用 有效&#xff1a;以更有效的方式使用计算机系统资源 扩展&#xff1a;方便用户有效开发、测试和引进新功能 操作系统的 作用&#xff1a; 1. 有效的管理资源 2.通过命令接口、编程接口等为用户提供各种…

【自然语言处理】【ChatGPT系列】Chain of Thought:从大模型中引导出推理能力

Chain-of-Thought Prompting&#xff1a;从大模型中引导出推理能力《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》论文地址&#xff1a;https://arxiv.org/pdf/2201.11903.pdf 相关博客 【自然语言处理】【ChatGPT系列】Chain of Thought&#xf…

什么是加权轮询?云解析DNS是否支持加权轮询?-中科三方

什么是加权轮询&#xff1f; 所谓的加权轮询算法&#xff0c;其实就是Weighted Round Robin&#xff0c;简称wrr。在我们配置Nginx的upstream的时候&#xff0c;带权重的轮询&#xff0c;其实就是wrr。 upstream backend { ip_hash; server 192.168.1.232 weight4; server 19…

无疫苗未吃药,48小时内阳康全纪实个案

为了不误导不同体质的人&#xff0c;特意强调这是个案&#xff0c;阳康方案仅供参考。小编体质偏寒&#xff0c;长期熬夜&#xff0c;黑白颠倒&#xff0c;有习惯性头痛症。经验总结&#xff1a;1.受到风寒是病发的直接导火索&#xff0c;就算携带病毒&#xff0c;本体没有受到…

Android实现红绿灯检测(含Android源码 可实时运行)

Android实现红绿灯检测(含Android源码 可实时运行) 目录 Android实现红绿灯检测(含Android源码 可实时运行) 1. 前言 2. 红绿灯检测数据集说明 3. 基于YOLOv5的红绿灯检测模型训练 4.红绿灯检测模型Android部署 &#xff08;1&#xff09; 将Pytorch模型转换ONNX模型 &…

吉林优美姿:抖音怎么增加销量?

为了更好的在做抖音好物联盟&#xff0c;那么一些抖音达人也会想方设法的去报名申请&#xff0c;那么大家是否真的清楚这个报名要怎么做呢&#xff1f;具体有什么要求呢&#xff1f;跟着吉林优美姿小编来一起看看吧&#xff01; 注册要求&#xff1a;凡注册抖音 APP并开通产品分…

大数据培训Impala之存储和压缩

注&#xff1a;impala不支持ORC格式 1.创建parquet格式的表并插入数据进行查询 [hadoop104:21000] > create table student2(id int, name string) > row format delimited > fields terminated by ‘\t’ > stored as PARQUET; [hadoop104:21000] > insert …

工控CTF之协议分析9——其他协议

协议分析 流量分析 主要以工控流量和恶意流量为主&#xff0c;难度较低的题目主要考察Wireshark使用和找规律&#xff0c;难度较高的题目主要考察协议定义和特征 简单只能简单得干篇一律&#xff0c;难可以难得五花八门 常见的工控协议有&#xff1a;Modbus、MMS、IEC60870、…

【计算机视觉】回顾2022年计算机视觉领域最激动人心的进展

目录&#xff1a;回顾2022年计算机视觉一、前言二、计算机视觉趋势2.1 Transformer统治计算机视觉2.2 以数据为中心的计算机视觉获得牵引力2.3 AI 生成的艺术作品2.4 多模态人工智能成熟三、计算机视觉的新应用3.1 运动领域3.2 环境保护3.3 自动驾驶3.4 健康与医药四、总结一、…

数据类型隐式转换导致的阻塞

背景 不合适的数据类型隐式转换会导致性能下降和并发下降&#xff0c;而且大多数技术人员对隐式转换的概念是陌生的&#xff0c;因此在生产环境中非常常见&#xff0c;通过本文做一个系统的梳理。 现象 收到SQL专家云阻塞告警邮件&#xff0c;登录SQL专家云&#xff0c;进入实…

推荐系统学习笔记-冷启动

简介 推荐系统的主要目标是将大量的标的物推荐给可能喜欢的海量用户, 这里涉及到标的物和用户两类对象。任何互联网推荐产品, 标的物和用户都是不断增长变化的&#xff0c;所以一定会频繁面对新标的物和新用户, 推荐系统冷启动问题指的就是对于新注册的用户或者新入库的标的物…

CDGA|2022年内有超20家银行因数据治理模块受罚,原因都在这里

今年&#xff0c;银保监会对银行数据治理的监管趋严&#xff0c;对银行机构在监管数据质量和数据报送中存在的违法违规行为&#xff0c;不断加大处罚与整治力度。 近日&#xff0c;北京农商银行收到的一张630万元罚单显示&#xff0c;该行主要存在的违法违规事实具体为&#xf…

NVMe解读

看NVMe协议&#xff08;1.0e&#xff09;过程中&#xff0c;参考了SSDFans的很多文章内容&#xff0c; 目录 1. 综述 3 1.1 名词解释 3 1.1.1 Namespace 3 1.1.2 Fused Operations 4 1.1.3 指令执行顺序 4 1.1.4 写单元的原子性 4 1.1.5 元数据 4 1.1.6 仲裁机制 4 1…

图数据库知识点3:图数据库解决了什么问题?

在前面的两个知识点中我们先后介绍了&#xff1a; 知识点1&#xff1a;图数据库与关系型数据库的区别 知识点2&#xff1a;图思维方式 现在,我们可以更进一步来通过具体的例子来了解图数据库、图计算到底解决了什么问题。我们先来剖析下面这个问题&#xff1a; 图数据库查询…

【Vue实用功能】elementUI 自定义表单模板组件

elementUI 实现一个自定义的表单模板组件 注&#xff1a;该功能基于elementUI 背景&#xff1a;在项目开发中&#xff0c;我们会遇到这种需求&#xff0c;在管理后台添加自定义表单&#xff0c;在指定的页面使用定义好的表单 直接上代码&#xff1a; <template><di…

DBCO-PEG-NHS, 可溶于水,有多种分子量供选择

凯新生物DBCO-PEG-NHS衍生物可以点击化学反应不需要任何金属催化剂。反应促进1,3-偶极环加成反应&#xff0c;环辛炔和叠氮化合物&#xff0c;也被称为铜自由点击反应&#xff0c;是一种生物正交反应使溶液中的两个分子的共轭。DBCO PEG衍生物具有缓冲溶液中快速的动力学和稳定…