回溯算法+对称剪枝——从八皇后问题到数独问题(二)
引入:
本节我们进一步完善八皇后问题,学习剪枝、八皇后残局问题 进一步领会逻辑编程的概念,深入体会回溯算法,回顾上一节提到的启发搜索策略。
回顾:
八皇后问题:我们需要在一个空棋盘上放置 n 个皇后,使得任意两个皇后不能在同一行、同一列或同一对角线上。
我们使用回溯算法逐行尝试放置皇后,并通过冲突检测剪枝无效的分支实现。
def spin(row): # 回溯算法def is_valid(row, col): def prt():# 主程序入口
spin(0) # 从第 0 行开始求解
print(f"总共有 {sol_num} 种解法。")
现在问题在于,当我们输入n=10时,解已经输出2680个了, 跑了大概十几秒钟才出来。这时我们发现,这其中很大一部分解之间是可以通过旋转对称得到的,如果能消除这些由旋转对称得到的解,是否能提高速度呢?
显然是可以的,在应用“对称剪枝”后,n=10的输出几乎是一瞬间的事。
那么,剪枝是什么呢?
剪枝
剪枝就是在搜索或计算过程中提前终止无效路径,从而减少不必要的计算。
我们在上一节似乎做过这件事!
# 尝试在当前行的每一列放置皇后
for col in range(n):if is_valid(row, col): # 如果当前位置有效board[row] = col # 放置皇后spin(row + 1) # 递归处理下一行board[row] = -1 # 回溯,撤销放置
没错,上一节设定is_valid()函数的手段就是剪枝!
通过is_valid()函数判断该节点是否有解,若无解返回 False,则直接跳过后续递归,因为从这个树杈长出去的其他枝干都无解,就剪枝了。
剪枝的类型
可行性剪枝:
当前节点不满足约束条件,则剪枝。
最优性剪枝:
求最优解时,若当前局部解已劣于已知最优解,则剪枝。
启发式剪枝:
利用经验规则(启发式函数)优先剪掉低概率分支。
还有接下来的
对称剪枝:
若两个解(或部分解)可以通过旋转、镜像、置换等对称操作相互转换,则它们是对称等价的。
对称剪枝的实现
显然,将棋盘沿对称轴分两半,从第一行看两侧的遍历路径总是一样的,因此我们考虑只计算一半情况的解。
但棋盘并不总是偶数X偶数的,遇到奇数怎么办?
很简单,单独计算中间这一行即可!
因此,当棋盘为偶数时,我们只计算第一行一半的解,如果是奇数,则加上中间一列产生的解:
# 对称性剪枝:限制第一行的皇后位置if n > 0:for col in range(n // 2): # 只考虑第一行的一半列board[0] = colspin(1) # 从第二行开始递归# 如果 n 是奇数,单独处理中间列if n % 2 == 1:board[0] = n // 2spin(1)
静态剪枝 VS 动态剪枝
你可能想问:为什么只对第一行剪枝,第二行第三行呢?是不是剪得越多算得越快呢?
实则不然,这就是对称剪枝策略的核心——通常我们只对搜索树的浅层(如第一行)进行静态剪枝。
我们之所以能对第一行对称剪枝是因为其对称性未被破坏,
而一旦放置皇后后,后续的对称性就会被破坏:例如第一行皇后放在列0,棋盘就会失去90°旋转对称性。
因此进行深层剪枝时,往往需要动态判断是否有某种对称性,其计算成本(包括分解和递归)和动态存储空间都是阶乘级的上涨。
结论:虽然动态剪枝减少了节点数,但增加的判断时间反而导致总耗时上升。
因此我们只对已知初始状态的第一行进行对称剪枝!
完整代码仅仅是在之前代码上添加了对称性剪枝这一部分:
def solve_n_queens(n):def is_valid(board, row, col):"""检查当前位置 (row, col) 是否有效"""for i in range(row): if board[i] == col or abs(i - row) == abs(board[i] - col):return Falsereturn Truedef spin(row):"""回溯函数"""nonlocal sol_numif row == n: # 如果所有行都放置了皇后sol_num += 1returnfor col in range(n):if is_valid(board, row, col): # 剪枝:只有有效位置才继续board[row] = col # 放置皇后spin(row + 1) # 递归处理下一行board[row] = -1 # 回溯,撤销放置# 初始化board = [-1] * n # board[i] 表示第 i 行中皇后所在的列号sol_num = 0# 对称性剪枝:限制第一行的皇后位置if n > 0:for col in range(n // 2): # 只考虑第一行的一半列board[0] = colspin(1) # 从第二行开始递归# 如果 n 是奇数,单独处理中间列if n % 2 == 1:board[0] = n // 2spin(1)return sol_numn = int(input("请输入棋盘大小 n:"))
sol_num = solve_n_queens(n)
print(f"总共有 {sol_num} 种解法。")
皇后残局问题
在一个 n x n 的国际象棋棋盘上,已放置若干皇后且互不攻击,需继续放置剩余皇后至 n 个,满足任意两皇后不在同一行、列或对角线上。
输入:
- 输入一个n,代表棋盘的大小。
- 输入一个二维 n x n 的棋盘状态,其中部分格子已经有皇后(用‘Q’表示),其余格子为空(用 '.' 表示)。
4
.Q..
...Q
....
....
输出:
- 如果存在解,则输出所有可能的完整解(即棋盘上放置了
n
个互不攻击的皇后)。 - 如果无解,则输出“无解”。
解法 1:
.Q..
...Q
Q...
..Q.共找到 1 种解法。
实现思路
我们考虑相较于一般皇后问题,残局问题做了哪些改变?我们应该如何应对?
(1) 初始棋盘状态
棋盘已经部分皇后——遍历棋盘,保留在board中。
(2) 约束条件
固定的皇后增加了约束条件:新皇后不仅要满足自身约束规则,还须与已固定的皇后兼容——输入时先对残局检查冲突,放入新皇后时直接跳过这些行。
(3) 解空间
固定的皇后减少了搜索空间——直接跳过。
若固定皇后间存在冲突,则直接无解。
因此,修改原思路:
① 初始化与解析:首先初始化容器并解析棋盘。
② 初始检查:检查初始棋盘自身是否冲突
③ 调用回溯函数:不冲突则调用回溯函数
④ 结束判断:回溯函数先检查当前是否满足结束条件(所有行都有皇后)
⑤ 遍历每一列:若这一列有固定皇后则跳过
⑥ 约束条件:否则判断是否满足约束条件。若满足,则保存当前状态,同时为了下一次遍历到这里时这一层是空的(有皇后就会被略过)要将这一层还原为空,接着处理下一行。
⑦ 如果不满足约束条件则自动判断当前是否是这一行的最后一个元素,如果是,证明这一行无论皇后放在哪都无解,因此自动返回上一行重新找解
⑧ 如果不是,就继续遍历下一列直到找到可以放皇后的位置。
代码实现:
一、初始化与解析:
初始化列表参考上一节:
# 初始化
board = [-1] * n # 当前棋盘状态(-1 表示未放置皇后)
solutions = [] # 存储所有解
sol_num = 0
首先考虑如何接收这个残局,
在上一节中,我们用列表board[]保存每一行皇后的位置,
因此我们的任务是如何从nxn的输入中读取Q的位置存进board[]列表中。
由于输入是 n x n 的,我们使用for_in_range(n)循环n次接收n行的输入,并将其存入初始表格initial_board[]中。
initial_board = [input().strip() for _ in range(n)] # 接收一维数组
其中 for _ in 仅表示循环 n 次,不关心当前迭代的索引,strip()去掉每一行输入的换行符。
输入后initial_board的内容是:
initial_board = ['.Q..', '...Q', '....', '....']
接着直接调用问题解决函数:
if __name__ == "__main__":n = int(input("请输入棋盘大小 n:"))print("请输入初始棋盘状态('Q' 表示皇后,'.' 表示空位):")initial_board = [input().strip() for _ in range(n)] # 接收一维数组solve_n_queens_with_given_board(n, initial_board)
接着是如何解析initial_board[]中皇后的位置,我们考虑遍历每一个元素“字符串”,在这个字符串中寻找是否有'Q'字符,如果有就在board对应位置保存,没有就跳过。
# 解析初始棋盘
for r in range(n):if initial_board第r元素有'Q':c = 'Q'的位置board[第r元素] = 'Q'的位置else:pass
那么如何从字符串中找指定字符呢?
我们想到index()函数,他会返回对象中与要找字符匹配的第一个元素的下标。
X = '1919810'
print(X.index('9'))
#输出1
代码也就很容易想到了:
# 解析初始棋盘for r in range(n):try:c = initial_board[r].index('Q') # 找到 'Q' 的列索引board[r] = c # 固定该位置except ValueError:pass # 如果该行没有 'Q',跳过
二、初始检查:检查初始棋盘自身是否冲突
由于上一节的约束条件在这里不变,因此保留is_valid()判断函数。
那么接下来的任务就是检查初始棋盘是否冲突了
刚刚我们将initial_board的内容放到了board中,因此我们对board每一元素遍历,如果其值不为-1证明这一行有固定皇后,触发冲突判断
is_valid()的参数列表是
def is_valid(board, row, col):
因此我们还要把当前位置传给他,假设遍历到第r行,且有'Q'元素,则其位置为board[r],即纵坐标为board[r]:
def is_valid(board, r, board[r]):
完整代码:
# 检查初始棋盘是否有冲突for r in range(n):if board[r] != -1: # 如果当前行有固定皇后if not is_valid(board, r, board[r]):print("无解")return
三、回溯算法:
由于固定皇后的存在,解空间减小了,因此遍历行时,会有两种情况:
①该行已有固定皇后,则检测是否冲突。
②该行为空,则和普通皇后问题一样进行列遍历找地方放皇后。
当然,在执行遍历行前,还要优先进行终点判定:
如果当前行是最后一行则将棋盘状态保存在result中,[:]代表选择全部。同时解数量加一。
if row == n: # 如果所有行都放置了皇后result.append(board[:])sol_num += 1return
对于情况①,如果固定皇后存在,则进行冲突判断。
由于我们在解析initial_board[]的时候已经记录过固定皇后的位置了,其实if下面那一行是多余的,但为了与情况②保存代码对称,我们依然保留。
if initial_board[row] != -1: # 如果当前行已经有固定的皇后if is_valid(board, row, initial_board[row]): # 检查是否冲突board[row] = initial_board[row]spin(row + 1)board[row] = -1else: # 如果冲突,则无解return
对于情况② ,如果该行为空,则正常进行列遍历,找合适位置放入皇后。
else: # 如果当前行没有固定的皇后for col in range(n):if is_valid(board, row, col): # 剪枝:只有有效位置才继续board[row] = col # 放置皇后spin(row + 1) # 递归处理下一行board[row] = -1 # 回溯,撤销放置
四、输出函数
你可能已经注意到了,我们找到解后并没有立马输出,而是保存在result[]中。
因此输出函数就是要从result[]中迭代输出解(用上一节的prt()也是可以的,星马想稍稍讲讲enumerate的用法)
首先先判断有没有解,直接看sol_num是否为零即可。
如果有解,就考虑如何从result中输出解。
在使用enumerate前,最重要的事就是确定迭代对象的结构是什么样的,即result是如何存储解的状态的?
还记得result是如何来的吗?我们直接将board的全部状态装载进去了。
result.append(board[:])
其结构就是由board[]构成的解空间。
result = [[1, 3, 0, 2], # 解法 1[2, 0, 3, 1] # 解法 2
]
接下来,我们的输出要求也是“解法X:解的结构”。
而result的存储格式正好是“解法:解的结构”的键值对结构!
enumerate迭代器用于在遍历容器时同时获取元素的索引和值,也就是说他能同时返回我们想要的东西。
语法为:
for index, value in enumerate(iterable, start=0):
index是索引键,value是对应值,我们分别取idx和sol。
后面的逻辑和皇后问题一样,先初始化 输出行 为“...........”,从对应解取对应存放Q的位置,更改为'Q'
for idx, sol in enumerate(result):print(f"解法 {idx + 1}:")for r in range(n):line = ['.'] * nline[sol[r]] = 'Q'print(' '.join(line))print()
完整代码:
# 输出结果
if sol_num == 0:print("无解")
else:for idx, sol in enumerate(result):print(f"解法 {idx + 1}:")for r in range(n):line = ['.'] * nline[sol[r]] = 'Q'print(' '.join(line))print()print(f"共找到 {sol_num} 种解法。")
至此,所有核心代码结束,接下来的任务就是装在一起就好啦~
我们将回溯函数、约束条件函数和执行逻辑全部封装在solve_n_queens_with_given_board这个函数中,由于我们要获取输入n和残局情况initial_board,因此要作为参数传入。
def solve_n_queens_with_given_board(n, initial_board):def is_valid(board, row, col):#约束条件判断def spin(row):#回溯函数#################################################################
调用solve_n_queens_with_given_board()后从这里开始执行,前面是函数声明# 初始化board = [-1] * n # 初始化当前棋盘状态(-1 表示未放置皇后)result = [] # 存储所有解sol_num = 0# 解析初始棋盘for r in range(n):# 检查初始棋盘是否有冲突for r in range(n):# 开始回溯spin(0)# 输出结果if sol_num == 0:无解else:输出解# 示例调用
if __name__ == "__main__":n = int(input("请输入棋盘大小 n:"))print("请输入初始棋盘状态('Q' 表示皇后,'.' 表示空位):")initial_board = [input().strip() for _ in range(n)] # 接收一维数组solve_n_queens_with_given_board(n, initial_board)
完整代码:
def solve_n_queens_with_given_board(n, initial_board):def is_valid(board, row, col):"""检查当前位置 (row, col) 是否有效"""for i in range(row): # 检查当前行之前的行if board[i] == col or abs(i - row) == abs(board[i] - col):return Falsereturn Truedef spin(row):"""回溯函数"""nonlocal sol_numif row == n: # 如果所有行都放置了皇后result.append(board[:])sol_num += 1returnif initial_board[row] != -1: # 如果当前行已经有固定的皇后if is_valid(board, row, initial_board[row]): # 检查是否冲突board[row] = initial_board[row]spin(row + 1)board[row] = -1else: # 如果冲突,则无解returnelse: # 如果当前行没有固定的皇后for col in range(n):if is_valid(board, row, col): # 剪枝:只有有效位置才继续board[row] = col # 放置皇后spin(row + 1) # 递归处理下一行board[row] = -1 # 回溯,撤销放置# 初始化board = [-1] * n # 当前棋盘状态(-1 表示未放置皇后)result = [] # 存储所有解sol_num = 0# 解析初始棋盘for r in range(n):try:c = initial_board[r].index('Q') # 找到 'Q' 的列索引board[r] = c # 固定该位置except ValueError:pass # 如果该行没有 'Q',跳过# 检查初始棋盘是否有冲突for r in range(n):if board[r] != -1: # 如果当前行有固定皇后if not is_valid(board, r, board[r]):print("无解")return# 开始回溯spin(0)# 输出结果if sol_num == 0:print("无解")else:for idx, sol in enumerate(result):print(f"解法 {idx + 1}:")for r in range(n):line = ['.'] * nline[sol[r]] = 'Q'print(' '.join(line))print()print(f"共找到 {sol_num} 种解法。")# 示例调用
if __name__ == "__main__":n = int(input("请输入棋盘大小 n:"))print("请输入初始棋盘状态('Q' 表示皇后,'.' 表示空位):")initial_board = [input().strip() for _ in range(n)] # 接收一维数组solve_n_queens_with_given_board(n, initial_board)
小结:
残局问题就是提前固定了几个皇后,只要合理解决冲突就能简单找到答案。本节还是希望诸位能体会回溯函数的变体和处理范式。
Ⅰ 剪枝就是提前终止,分为 可行 最优 启发 对称剪枝。
Ⅱ 一般对称剪枝只处理第一行,因为深层剪枝会破坏对称性。动态剪枝的开销反而更大。
Ⅲ 接收二维数组可以用一维字符串数组:[input().strip() for _ in range(n)],n为接收批次数。
Ⅳ 从字符串找某字符索引用index('X')
Ⅴ Enumerate的用法:
① 确定存储对象的结构。
② 根据for 索引, 对应值 in enumerate(result):获取键值对。
写在后面:
很开心你能耐着性子读到这里,很荣幸能将我的三脚猫知识分享给大家。
星马也是小白,因此更懂小白的心思,大佬认为一眼明白的代码和思路可能在我们眼中就是鸿沟。这篇文章也还有很多不足之处,或是纰漏,希望你发现了及时在评论区提醒我呀~
(人工智能学院就是每周四五天满课的啦,因此更新基本随缘~)
星马是刚入门的大菜比,有错望指正,有项目可以带带我
相关文章:
回溯算法+对称剪枝——从八皇后问题到数独问题(二)
引入: 本节我们进一步完善八皇后问题,学习剪枝、八皇后残局问题 进一步领会逻辑编程的概念,深入体会回溯算法,回顾上一节提到的启发搜索策略。 回顾: 八皇后问题:我们需要在一个空棋盘上放置 n 个皇后&a…...
基于 Spring Boot 瑞吉外卖系统开发(三)
基于 Spring Boot 瑞吉外卖系统开发(三) 分类列表 静态页面 实现功能所需要的接口 定义Mapper接口 Mapper public interface CategoryMapper extends BaseMapper<Category> {}定义Service接口 public interface CategoryService extends ISe…...
Pascal VOC 2012 数据集格式与文件结构
Pascal VOC 2012 1 Pascal VOC 2012 数据集1.1 数据集概述1.2 文件结构1.3 关键文件和内容格式(1) Annotations/ 目录(2) ImageSets/ 目录(3) JPEGImages/ 目录(4) SegmentationClass/ 和 SegmentationObject/ 目录 1.4 标注格式说明(1) 目标检测标注(2) 语义分割标注(3)实例分…...
11:00开始面试,11:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
MySQL与Oracle字段类型对比及迁移指南
文章目录 MySQL与Oracle字段类型对比及迁移指南1. 核心字段类型对照表2. 常见函数对照表2.1 字符串函数2.2 日期函数2.3 数值函数2.4 类型转换函数2.5 空值处理函数2.6 其他常用函数3. 迁移配置细则4. 迁移工具推荐5. 常见问题解决方案6. 性能优化建议MySQL与Oracle字段类型对比…...
Spring MVC 处理 HTTP 状态码、响应头和异常的完整示例
Spring MVC 处理 HTTP 状态码、响应头和异常的完整示例 1. 正常响应处理 通过 ResponseEntity 可以灵活控制 HTTP 状态码、响应头和响应体。 代码示例:创建资源返回 201 并设置 Location 头 import org.springframework.http.HttpHeaders; import org.springfram…...
http页面的加载过程
HTTP/2 核心概念 1.1 流(Stream) • 定义:HTTP/2 连接中的逻辑通道,用于传输数据,每个流有唯一标识符(Stream ID)。 • 特点: ◦ 支持多路复用(多个流并行传输&#…...
动手人形机器人(RL)
1 PPO的讲解 核心步骤,如策略网络和价值网络的定义、优势估计、策略更新、价值更新等基础功能的实现 2 代码构成 可能涉及 初始化,Behavior Clone 3 动手强化学习 import pytorch as torch class actorcritic ##等待补充 4 PD Gains 在机器人学中&…...
使用RabbitMQ实现异步秒杀
搭建RabbitMQ 在虚拟机上用docker搭建RabbitMQ,首先拉取镜像 docker run --privilegedtrue -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management mkdir -p /usr/local/docker/rabbitmq再创建rabbitmq容器,下面的命令已经能够创建之后…...
基于PyQt5的企业级生日提醒系统设计与实现
在企业人力资源管理场景中,员工生日提醒是一项重要的关怀功能。本文将以一个基于PyQt5开发的生日提醒系统为例,深入解析桌面应用程序开发中的关键技术实现,涵盖GUI设计、数据持久化、系统集成、动画效果等核心模块。 一、技术选型分析 1.1 PyQt5框架优势 跨平台特性:支持W…...
蓝桥杯嵌入式第16届——ADC模数转化部分
将外部的模拟信号转换为数字信号 ( ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 ) STM32 - ADC 笔记_stm32 adc电容-CSDN博客 引脚状况 STM32cubemx配置 ADC1配置 ADC2配置 代码部分 …...
拜特科技签约天津城投集团,携手共建司库管理系统
近日,拜特科技成功签约天津城市基础设施建设投资集团有限公司(以下简称“天津城投集团”),携手共建司库管理系统。 自2015年结缘以来,拜特科技与天津城投集团已携手并进十年,构建了稳固且高效的合作桥梁。…...
Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题
Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题 在使用 Knife4j 为 Spring Boot 项目生成 API 文档时,开发者可能会遇到文件上传功能不显示文件域的问题。本文将详细介绍如何解决这一问题,并提供完整的解决方案。 Knife4j官网…...
Nuxt.js的useHead有哪些对象
在Nuxt.js框架中,useHead是一个用于操作页面<head>部分的辅助函数。它返回一个包含多个对象的集合,允许你轻松地在组件中修改或添加 HTML 的<head>内容。 具体来说,useHead 返回的对象集合包括: title: 用于设置页面…...
JavaScript的可选链操作符 ?.
JavaScript的可选链操作符(Optional Chaining Operator)是 ES2020(ES11) 引入的新特性,通过语法 ?. 简化对深层嵌套对象属性、方法或数组元素的访问,避免因中间值为 null 或 undefined 而引发的错误。 核…...
增长黑客:激活实验助力增长
激活实验是推动用户增长的重要手段。下面为大家详细介绍激活实验的关键步骤与重点解决问题 激活实验的三个关键步骤 1. 明晰 “啊哈时刻” 路径 “啊哈时刻” 指用户瞬间领悟产品价值的瞬间。要达成这一点,需明确用户体验到 “啊哈时刻” 的所有路径。以在线绘图工具…...
STM32低功耗
设置不同位来配置是哪种低功耗模式 WAKEUP引脚可以唤醒任何睡眠状态,但是只有待机模式是属于WAKEUP唤醒,其他模式都是属于中断唤醒,所以待机模式要使能EWUP引脚,还要手动清除唤醒标志位(在进入待机模式前就要清除标志位ÿ…...
【精品PPT】2025固态电池知识体系及最佳实践PPT合集(36份).zip
精品推荐,2025固态电池知识体系及最佳实践PPT合集,共36份。供大家学习参考。 1、中科院化学所郭玉国研究员:固态金属锂电池及其关键材料.pdf 2、中科院物理所-李泓固态电池.pdf 3、全固态电池技术研究进展.pdf 4、全固态电池生产工艺.pdf 5、…...
头歌数据库【数据库概论】第10-11章 故障恢复与并发控制
第1关:数据库恢复技术 1、事务的( A)特性要求事务必须被视为一个不可分割的最小工作单元 A、原子性 B、一致性 C、隔离性 D、持久性 2、事务的(C )特性要求一个事务在执行时,不会受到其他事务的影响。 A、原…...
qt之opengl使用
使用qt中的openglWidget绘制一个三角形。自定义的类继承关系sunOpengl : public QOpenGLWidget,QOpenGLFunctions_3_3_Core 代码如下 /*----MainWindow.cpp----------------------------------------------*/ #include "mainwindow.h" #include "./ui_mainwin…...
Spark Core编程
一 Spark 运行架构 1 运行架构 定义 Spark 框架的核心是一个计算引擎,整体来说,它采用了标准 master-slave 的结构 如图所示 2 核心组件 Spark 框架有两个核心组件: 1)Driver 2)Spark 驱动器节点(用于执行 Spark 任务中的 main 方法&…...
蓝桥杯 B3619 10 进制转 x 进制
题目描述 给定一个十进制整数 n 和一个小整数 x。将整数 n 转为 x 进制。对于超过十进制的数码,用 A,B ... 表示。 输入格式 第一行一个整数 n; 第二行一个整数 x。 输出格式 输出仅包含一个整数,表示答案。 输入输出样例 …...
spring mvc中不同服务调用类型(声明式(Feign)、基于模板(RestTemplate)、基于 SDK、消息队列、gRPC)对比详解
RestControllerAdvice 和 ControllerAdvice 对比详解 1. 基本概念 注解等效组合核心作用ControllerAdviceComponent RequestMapping(隐式)定义全局控制器增强类,处理跨控制器的异常、数据绑定或全局响应逻辑。RestControllerAdviceControll…...
敏捷迭代实战经验分享
一、敏捷迭代团队成员构成 比较高效的敏捷开发团队人员一般保持在7~10人左右,一般一个完整的敏捷迭代团队包含PM、BA、开发、测试、设计5类角色成员,由于不同项目的现状不同,可根据现实情况配置相应角色。 图:项目核心团队角色 二、敏捷实践活动 敏捷迭代的周期可以根据各…...
《从底层逻辑剖析:分布式软总线与传统计算机硬件总线的深度对话》
在科技飞速发展的当下,我们正见证着计算机技术领域的深刻变革。计算机总线作为信息传输的关键枢纽,其发展历程承载着技术演进的脉络。从传统计算机硬件总线到如今备受瞩目的分布式软总线,每一次的变革都为计算机系统性能与应用拓展带来了质的…...
服务器运维ACL访问控制列表如何配置
ACL(访问控制列表)在服务器运维中用于细粒度地控制用户或主机对资源的访问权限。正确配置ACL能有效限制未授权访问,增强系统安全性。以下是ACL的基本配置流程及示例,主要以Linux系统为例进行说明。 一、启用ACL支持 1. 检查文件系统是否支持ACL tune2fs …...
PIXOR:基于LiDAR的3D检测模型解析
目录 1、前言 2、PIXOR介绍 2.1. 什么是PIXOR? 2.2. PIXOR如何工作? 3、表现和应用 3.1、PIXOR的性能表现 3.2、PIXOR的应用场景 3.3、PIXOR的局限性与挑战 4. PIXOR的未来展望 5. 结语 1、前言 自动驾驶技术正以前所未有的速度发展ÿ…...
【OSG学习笔记】Day 2: 场景图(Scene Graph)的核心概念
今天课程分为两部分,第一部分我们学习一下Scene Graph理论知识,第二部分我们熟悉下OSG的源码。 第一部分(Scene Graph) 在OpenSceneGraph中,场景图(Scene Graph)通过树状层级结构高效管理3D对…...
虚幻5的C++调试踩坑
本地调试VS附加调试 踩坑1 预编译版本的UE5没有符号文件,无法调试源码 官方代码调试所需要的符号文件bdp需要下载导入。我安装的5.5.4是预编译版本,并非ue5源码。所以不含bdp文件。需要调试官方代码则需要通过EPIC中下载安装。右键UE版本,打…...
【软件测试】自动化测试框架Pytest + Selenium的使用
Pytest Selenium 是一种常见的自动化测试框架组合,用于编写和执行 Web 应用程序的自动化测试。Pytest 是一个强大的 Python 测试框架,而 Selenium 是一个用于浏览器自动化的工具,二者结合使用可以高效地进行 Web 应用的功能测试、UI 测试等。…...
蓝桥杯补题
方法技巧: 1.进行循环暴力骗分,然后每一层的初始进行判断,如果已经不满足题意了,那么久直接continue,后面的循环就不用浪费时间了。我们可以把题目所给的等式,比如说有四个未知量,那么我们可以用…...
2025年港口危货储存单位主要安全管理人员备考练习题
港口危货储存单位主要安全管理人员备考练习题: 单选题 1、依据《安全生产法》,危险物品的生产、储存单位的安全生产管理人员的任免,应当告知( )。 A. 主管的负有安全生产监督管理职责的部门 B. 当地人民政府 C. 行…...
openEuler欧拉系统配置local的yum源
1.下载iso openEuler | 开源社区 | openEuler社区官网 2.上传openEuler镜像文件至服务器(例如上传至/home目录) 3.创建挂载目录 #mkdir -p /mount/iso 4.镜像挂载 #mount -o loop /home/openEuler-22.03-LTS-x86_64-dvd.iso(镜像上传目…...
AI比人脑更强,因为被植入思维模型【52】福格行为模型
giszz的理解:重要公式,是BMAT,行为动机能力触发点。也许是乘以。这个挺深刻的,在产品设计中,界面交互,都可以用到这样的思维模型。 一、定义 福格行为模型(Fogg Behavior Model)是由…...
DocLayout-YOLO:通过多样化合成数据与全局-局部感知实现文档布局分析突破
论文地址:https://arxiv.org/pdf/2410.12628 目录 一、论文概览:当YOLO遇见文档分析 二、创新点解析:两大核心技术 创新点1:Mesh-candidate BestFit合成算法 创新点2:全局-局部可控感知模块(GL-CRM) 三、实验结果:全面超越SOTA 主要指标对比(D4LA数据集) 消融…...
栈(算法)
在 C 里,栈是一种遵循后进先出(LIFO)原则的数据结构。下面从多个方面为你介绍 C 栈: 1. 使用标准库中的std::stack C 标准库提供了std::stack容器适配器,能方便地实现栈的功能。以下是简单示例: cpp #in…...
leetcode每日一题:子数组异或查询
引言 今天的每日一题原题是3375. 使数组的值全部为 K 的最少操作次数,比较水,可以分成2种情况: 存在比k更小的数,由于每次操作只能使得部分数变小,但是不能把任何数变大,所以肯定无法达成 不存在比k更小的…...
openEuler-22.03-LTS-SP3-x86_64 离线编译安装 nginx 1.20.1
openEuler-22.03-LTS-SP3-x86_64 离线编译安装 nginx 1.20.1 一、概述二、安装依赖1、安装 pcre、pcre-devel2、安装 zlib、zlib-devel3、安装 make、gcc、gcc-c3、编译 openssl5、安装 libtool6、编译 pcre-8.45 三、下载编译 nginx四、运行 nginx 一、概述 本文档适用于无法…...
使用Alamofire下载网站首页内容
用Alamofire库写一个下载网站首页内容的Swift代码。首先,我需要确认用户的需求。他们可能是在开发一个iOS应用,需要从某个网站获取首页的数据,比如HTML内容或者API数据。Alamofire是一个常用的Swift网络库,基于URLSession…...
服务器DNS失效
服务器异常 xx.t.RequestException: java.net.UnknownHostException: test.ac.xxxx.cn现象分析 本地测试正常,说明域名本身无问题。服务器 DNS 解析异常,导致 UnknownHostException。**服务器可正常解析 ****baidu.com**,说明网络正常&#…...
#无类域间路由(快速复习版)
判断两个无类(CIDR)地址是否属于同一个子网 🎯 问题本质: 判断两个 IP 地址是否属于同一个子网,其实就是 对比它们的“网络地址”是否相同。 🔍 原理步骤(通用方法) 我们按步骤来判…...
【Linux】jumpserver开源堡垒机部署
JumpServer 安装部署指南 本文档详细记录了 JumpServer 安装部署的过程、核心脚本功能说明以及后续管理使用提示,方便运维人员快速查阅和二次安装。 1. 前提条件 操作系统要求: 仅支持 Linux 系统,不支持 Darwin(macOS࿰…...
Memcached缓存系统:从部署到实战应用指南
#作者:猎人 文章目录 一、安装libevent二、安装配置memcached三、安装Memcache的PHP扩展四、使用libmemcached的客户端工具五、Nginx整合memcached:六、php将会话保存至memcached Memcached是一款开源、高性能、分布式内存对象缓存系统,可应用各种需要缓…...
【rdma tx data flow问题】
rdma data flow问题 1 SQ_doorbell如何产生? --RDMA网卡doorbell寄存器触发;2 CPU如何访问网卡的Doorbell寄存器?3 为什么需要roce_qid_convert把local_qid转换成global_qid;4.WQE的format是什么?5.WQE在网卡硬件中的处理流程&…...
Vue 框架组件间通信方式
组件间通信方式 不管是 vue2 还是 vue3,组件通信方式很重要,以下是常见的几种通信方式: props:可以实现父子组件、子父组件、甚至兄弟组件通信自定义事件:可以实现子父组件通信全局事件总线 $bus:可以实现…...
React 第三十节 使用 useState 和 useEffect Hook实现购物车
不使用 redux 实现 购物车案例 使用 React 自带的 useState 和 useEffect Hook 即可实现购物车 export default function ShoppingCar() {// 要结算的商品 总数 以及总价const [totalNum, setTotalNum] useState(0)const [totalPerice, setTotalPerice] useState(0)// 商品…...
卷积神经网络CNN
目录 一、图像基础知识 图像基本概念 图像的加载 二、CNN概述 CNN概述 三、卷积层 卷积计算 Padding Stride 多通道卷积计算 PyTorch卷积层API 四、池化层 池化层计算 Stride Padding 多通道池化层计算 PyTorch 池化 API 五、图像分类案例 CIFAR10 数据集 …...
【大数据生态】Hive的metadata服务未开启
解决办法 进入到Hive的bin目录下,键入命令: #启动元服务 [atguiguhadoop102 bin]$ pwd /opt/module/hive-3.1.2/bin [atguiguhadoop102 bin]$ ./hive --service metastore & #启动hive [atguiguhadoop102 hive-3.1.2]$ pwd /opt/module/hive-3.1.2 [atguiguhadoop102 hiv…...
【RabbitMQ】死信队列
1.概述 死信,顾名思义就是无法被消费的消息,也就是没有被传到消费者的消息,或者即使传到了也没有被消费。当然有死信就有死信队列。死信队列就是用来存储死信的。 它的应用场景就是保证订单业务的消息数据不丢失,当消息消费发 生…...
区间 dp 系列 题解
1.洛谷 P4342 IOI1998 Polygon 我的博客 2.洛谷 P4290 HAOI2008 玩具取名 题意 某人有一套玩具,并想法给玩具命名。首先他选择 W, I, N, G 四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用 W, I, N, G …...