算法——舞蹈链算法
一,基本概念
算法简介
舞蹈链算法(Dancing Links,简称 DLX)是一种高效解决精确覆盖问题的算法,实际上是一种数据结构,可以用来实现 X算法,以解决精确覆盖问题。由高德纳(Donald E. Knuth)提出 。
精准覆盖
什么是精确覆盖(Exact Cover)问题呢?就是在一个全集X中若干子集的集合为S。S* 是 S的一个子集,当且仅当X中的每一个元素在S*中恰好出现一次时,S*称之为一个精确覆盖。在计算机科学中,精确覆盖问题指找出这样的一种覆盖,或证明其不存在。这是一个NP-完全问题。
舞蹈链
其实是一种特殊的数据结构,用于高效地实现对精确覆盖问题的求解。它基于双向循环链表,每个节点除了包含指向左右节点的指针外,还包含指向上方和下方节点的指针,这种结构使得在搜索过程中能够快速地对链表进行插入、删除和恢复操作。
数据结构设计
每个1的节点包含四个指针:left
, right
, up
, down
,形成双向十字链表。
每列有一个列头节点,记录该列中1的数量(用于优化搜索顺序)。
算法流程
-
选择列:优先选择当前剩余1最少的列(减少搜索分支)。
-
覆盖列:删除该列及其关联的所有行(避免后续搜索冲突)。
-
递归搜索:对剩余矩阵重复上述步骤。
-
回溯恢复:若当前路径无解,恢复被删除的列和行,尝试其他分支。
- 结束条件:当舞蹈链中的所有列都被覆盖(即矩阵中所有列都被删除)时,找到了一个精确覆盖解;如果遍历完所有可能的分支都没有找到解,则说明该问题无解。
二,示例
例如,S = {A,B,C,D,E,F} 是全集 X = {1,2,3,4,5,6,7} 的一个子集的集合,其中:
A = {1, 4, 7}
B = {1, 4}
C = {4, 5, 7}
D = {3, 5, 6}
E = {2, 3, 6, 7}
F = {2, 7}
那么,S的一个子集 S* = {B, D, F} 是X的一个精确覆盖,因为 X 中的每个元素恰好在S*中出现了一次。
可以用0-1矩阵来表示精确覆盖问题。我们用矩阵的每行表示S的一个元素,也就是X的一个子集;用矩阵的每列表示X的一个元素。矩阵中的1代表这一列的元素存在于这一行对应的子集中,0代表不存在。那么精确覆盖问题可以转化成求出矩阵若干行的集合,使得集合中的每一列恰好都有一个1。
比如前面的问题可以用矩阵的形式表示成
那么选择红色的B,D,F能满足每列都恰好包含一个1。
可以用 Knuth 提出的X算法来解决精确覆盖问题。X算法是一个非确定性的深度优先回溯算法。它的具体步骤如下:
1. 如果矩阵
为空(没有任何列),则当前局部解即为问题的一个解,返回成功;否则继续。
2. 根据一定方法选择第 c 列。如果某一列中没有 1,则返回失败,并去除当前局部解中最新加入的行。
选择第 r 行,使得
(该步是非确定性的)。
将第 r 行加入当前局部解中。
对于满足
的每一列j,从矩阵
中删除所有满足
的行,最后再删除第 j 列。
对所得比 A 小的新矩阵递归地执行此算法。
让我们用 X算法解决上面的精确覆盖问题。
首先,当前矩阵不为空,算法继续进行。那么先选择1最少的一列。因为 1,2,3,5,6 列都只有 2 个 1,因此我们随便选择 1 个,比如第 1 列。
行 A 和 B 都含有 1,因此要在这两行中进行选择。
先尝试选择行 A。将行A加入到当前的解中。
行A的 1,4,7 列为 1,根据第 5 步,需要把所有在 1,4,7 列中含有 1 的行都删除掉,因此需要删除掉行A,B,C,E,F,同时删除掉第 1,4,7 列
删除之后,矩阵只剩下行 D 和第 2,3,5,6 列:
进入递归,回到第 1 步,矩阵非空,算法继续执行。
再进入第2步,此时选择 1 最少的第 2 列,里面没有 1,因此返回失败,同时将行 A 从当前的解中移除;
算法进入另一个分支,选择行 B,并将其加入到当前的解中:
行 B 的第 1,4 列为 1,因此要把 1,4 列中包含 1 的行都删掉。需要删除掉行 A,B,C,再删除掉 1,4 列。
此时矩阵变为
进入递归,回到第 1 步,矩阵非空,因此算法继续。
当前包含 1 最少的一列是第 5 列,那么将从第 5 列中选择含有 1 的行进行搜索。
第 5 列中行 D 含有 1,因此选择行 D,将其加入当前解中,算法进入新的一层搜索。
行 D 的第 3,5,6 列包含 1,我们要删掉这几列中包含 1 的所有行,同时删掉这几列
那么我们需要删掉行 D,E 和第 3,5,6 列,矩阵变为
再次递归执行,回到第 1 步,矩阵非空,因此算法继续
选择当前包含 1 最少的一列,这里选择第 2 列。第 2 列中只有行 F 包含 1, 因此选择行 F
将行 F 加入到当前解中,算法进入第 3 层搜索
行 F 中第 2,7列为 1,第 2,7 列中行 F 包含 1,因此移除行 F 和第 2,7 列
算法再次进入递归执行,回到第 1 步,此时所有的列都被移除了,矩阵为空,因此返回成功,找到了一个解:{B, D, F}
继续搜索,没有其他可以选择的行,返回上一层;
第2层也没有其他可以选择的行,再返回上一层;
第1层也没有其他可以选择的行,再返回上一层;
第0层也没有其他可以选择的行,算法终止。
以上就是 X 算法的执行过程。Knuth 提出 X 算法主要是为了说明舞蹈链的作用,他发现用舞蹈链来执行 X 算法效率特别高。那么什么是舞蹈链呢?它是基于双向链表的一种数据结构。
让我们先来看看双向链表:
上图是一个简单的双向链表,每个节点有两个指针,分别指向自己的前驱和后继节点。那么如果我们想把其中一个节点,比如 B 从链表中删掉,只需要执行下面的操作:
B.left.right = B.rightB.right.left = B.left
注意:此时虽然 B 从链表中移除了,但它的两个指针依然保持不变,还是指向之前的前驱和后继节点。
因此,如果我想把 B 再添加到链表原来的位置上,此时并不需要修改 B 的指针,只需要再把 B 的前驱和后继节点的指针恢复就可以了:
B.left.right = BB.right.left = B
理解了这一点之后,让我们再来看看舞蹈链的结构是怎么样的:
上面这个图是一个舞蹈链的结构,描述的是前面 X 算法中用到的矩阵。它由几部分构成:
最上面的蓝色部分是一个水平的环状双向链表。最左边是头节点,它是整个数据结构的根节点。其余是列头节点,每个代表矩阵中的一列。
每一列又是一个纵向的环状双向链表。除了最上面的列头节点,其他的每个节点都代表前面的矩阵中的一个 1。这实际上是一个稀疏矩阵,为了优化存储和效率,只保留了值为 1 的节点,把每个节点按顺序保存到数组中。最早的 Dancing Links 算法,也就是 Knuth 在 2000 年发表的论文中,下面的每一行也都是一个双向链表。但后来他发现每一行在算法执行过程中实际上不会发生变化,因此他把水平的双向链表取消了,只保留了最顶上的列头节点之间的水平双向链表。下面的每一行之间的前后节点可以直接通过数组的索引得到。两边是Space节点,用来标记一行的开始和结束。
每个普通节点 A 都包含 4 个 字段,A.up 和 A.down 代表双向链表的两个指针,分别指向 A 上面和下面的节点。还有一个 A.col ,指向 A 所在列的头节点,需要根据这个字段定位到节点所在的列。另外还有一个 A.row,主要是方便在递归的过程中缓存当前的解。
列头节点还要再多几个字段,left 和 right 分别指向水平双向链表的左节点和右节点。另外还有一个 count 字段,代表这一列当前一共有几个元素。X 算法的第 2 步,选择 1 最少的列时会用到这个字段。
理解了舞蹈链的数据结构之后,我们再来看看是怎样用舞蹈链来实现 X 算法的。这部分算法很精妙,也是舞蹈链这个名字的来由,通过对链表上的节点反复删除和插入实现了递归的回溯,就好像一个个链表在舞台上翩翩起舞一样。
具体的算法实现可以参照 Knuth 的论文,我们还是用图的方式来说明一下。
(1)首先,判断链表是否为空,可以通过 head.right == head 来判断。如果为空则返回,并输出当前的解。
(2)不为空则选择当前节点数最少的列。如果只有列头节点,则返回失败。
遍历这一列的每个节点,开始进行覆盖操作:
(1)首先将节点所在行作为解的一部分,加入到当前解中;
(2)遍历这一行的所有节点,将每个节点所在列都删除掉,同时删除掉与这些列有交集的所有行:
2a. 遍历节点所在列的每个节点,将每个节点所在行的所有节点从它所在的列中移除掉,同时将列头节点的计数减 1:
node.up.down = node.downnode.down.up = node.upcol_node.count -= 1
2b. 还要将这一列从链表中移除:
col_node.left.right = col_node.rightcol_node.right.left = col_node.left
进入递归调用,判断链表是否为空;
不为空则选择节点数最少的列,再遍历这一列的节点,进行覆盖操作:
移除掉所有节点之后,进入递归调用,发现链表不为空,但节点数最少的列中没有普通节点了,返回失败;
开始做链表的还原操作。注意还原的顺序需要和移除的顺序相反。如果我们是从上至下,从左至右移除节点,那么还原的时候就从右至左,从下至上。否则的话可能会出现问题,导致一个节点被还原多次,这样列中节点的计数就不准确了。
node.up.down = nodenode.down.up = nodecol_node.count += 1
并且把删除的列也取消覆盖
col_node.left.right = col_nodecol_node.right.left = col_node
递归返回到上一层,还原之后,发现列中没有其他节点可以选择,再返回到上一层,选择下一个节点所在的行。
和之前的方法相同,遍历这一行的所有节点,将每个节点所在列都删除掉,同时删除掉与这些列有交集的所有行:
再选择节点最少的列,遍历这一列的所有节点的所在行:
遍历这一行的所有节点,删除掉每个节点所在列,以及与这些列有交集的所有行:
再次进入递归调用,判断矩阵不为空,选择节点最少的一列,遍历每个节点,删除掉所在行的所有列,与这些列有交集的所有行,最后我们得到一个空矩阵。
此时将得到的解输出,并返回,接下来还要进行还原操作,然后搜索下一个解。
三、代码
class Node:def __init__(self):self.left = self.right = self.up = self.down = selfself.column = None # 列头节点self.row = None # 行标识def solve(matrix):# 构建舞蹈链head = build_dancing_links(matrix)solution = []search(head, solution)def search(head, solution):if head.right == head:# 找到解,输出结果return True# 选择1最少的列col = choose_column(head)cover(col)# 遍历该列的每一行row_node = col.downwhile row_node != col:solution.append(row_node.row)# 覆盖该行关联的所有列right_node = row_node.rightwhile right_node != row_node:cover(right_node.column)right_node = right_node.right# 递归搜索if search(head, solution):return True# 回溯solution.pop()left_node = row_node.leftwhile left_node != row_node:uncover(left_node.column)left_node = left_node.leftrow_node = row_node.downuncover(col)return False
class Node:def __init__(self):self.left = self.right = self.up = self.down = selfself.col = self.row = Noneclass DLX:def __init__(self):self.root = Node()self.columns = {}self.answer = []def add_column(self, name):node = Node()node.col = nodenode.row = Nonenode.left = self.root.leftnode.right = self.rootself.root.left.right = nodeself.root.left = nodeself.columns[name] = nodedef add_row(self, row_data):first = Nonelast = Nonefor col_name, value in row_data.items():if value == 1:node = Node()node.col = self.columns[col_name]node.row = row_datanode.up = node.col.upnode.down = node.colnode.col.up.down = nodenode.col.up = nodeif first is None:first = nodeelse:last.right = nodenode.left = lastlast = nodefirst.left = lastlast.right = firstdef cover_column(self, col):col.right.left = col.leftcol.left.right = col.righti = col.downwhile i!= col:j = i.rightwhile j!= i:j.down.up = j.upj.up.down = j.downj = j.righti = i.downdef uncover_column(self, col):i = col.upwhile i!= col:j = i.leftwhile j!= i:j.down.up = jj.up.down = jj = j.lefti = i.upcol.right.left = colcol.left.right = coldef search(self, k):if self.root.right == self.root:print("Solution found:", self.answer)return Truec = self.root.righti = c.downmin_size = float('inf')while i!= c:size = 0j = i.rightwhile j!= i:size += 1j = j.rightif size < min_size:min_size = sizec = ii = i.downself.cover_column(c.col)i = c.downwhile i!= c:self.answer.append(i.row)j = i.rightwhile j!= i:self.cover_column(j.col)j = j.rightif self.search(k + 1):return Trueself.answer.pop()i = i.downj = i.leftwhile j!= i:self.uncover_column(j.col)j = j.leftself.uncover_column(c.col)return False
运行
# 使用示例
dlx = DLX()
dlx.add_column('C1')
dlx.add_column('C2')
dlx.add_column('C3')
dlx.add_row({'C1': 1, 'C2': 0, 'C3': 1})
dlx.add_row({'C1': 0, 'C2': 1, 'C3': 1})
dlx.add_row({'C1': 1, 'C2': 1, 'C3': 0})
dlx.search(0)
四、算法优势
-
高效剪枝:通过列头节点统计剩余1的数量,优先选择约束最强的列,大幅减少搜索空间。
-
快速状态恢复:链表删除和恢复的时间复杂度为O(1),回溯代价极低。
-
通用性:适用于所有可转化为精确覆盖的问题。
五、应用领域
- 数独求解:数独问题可以很自然地转化为精确覆盖问题,舞蹈链算法能够快速有效地解决数独谜题,无论是人工设计的数独题目还是大规模生成数独游戏。
- 计算机视觉:在图像分割、目标识别等任务中,舞蹈链算法可用于解决一些组合优化问题,例如将图像中的像素点精确地划分到不同的目标区域。
- 网络设计:在网络拓扑设计、资源分配等方面,舞蹈链算法可以帮助找到满足特定要求的最优网络配置方案,例如在保证网络连通性的前提下,合理分配网络设备和链路资源。
-
N皇后问题:将棋盘转化为精确覆盖矩阵。
-
拼图游戏:如俄罗斯方块填充、多米诺骨牌覆盖等。
总结
舞蹈链算法通过双向链表的动态调整,将精确覆盖问题的搜索效率提升到极致。尽管实现复杂,但它在处理组合优化问题时表现卓越,尤其适合约束严格的场景。理解其核心在于掌握链表操作与回溯思想的结合。
相关文章:
算法——舞蹈链算法
一,基本概念 算法简介 舞蹈链算法(Dancing Links,简称 DLX)是一种高效解决精确覆盖问题的算法,实际上是一种数据结构,可以用来实现 X算法,以解决精确覆盖问题。由高德纳(Donald E.…...
Java状态机
目录 1. 概念 2. 定义状态机 3. 生成一个状态机 4. 使用 1. 概念 在Java的应用开发里面,应该会有不少的人接触到一个业务场景下,一个数据的状态会发生多种变化,最经典的例子例如订单,当然还有像用户的状态变化(冻结…...
3.1 Hugging Face Transformers快速入门:零基础到企业级开发的实战指南
Hugging Face Transformers快速入门:零基础到企业级开发的实战指南 一、Transformers库:NLP领域的"瑞士军刀" 1.1 核心能力全景 预训练模型库:支持150,000+模型(BERT、GPT、T5等)统一API设计:3行代码完成文本分类、生成、翻译等任务多模态支持:文本、图像、音…...
Java+SpringBoot+数据可视化的家庭记账小程序(程序+论文+安装+调试+售后等)
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统介绍 在当下这个科技日新月异、经济蓬勃向上的时代,中国经济正以令人瞩目的速度迅…...
Java-数据结构-(HashMap HashSet)
一、Tree和Hash的区别 在上一篇文章中,我们讲到了"TreeMap"和"TreeSet",但当我们刷题的时候却会发现,实际应用Map和Set时,却常常都只会用"HashMap"和"HashSet",这是为什么呢…...
【Prometheus】prometheus结合pushgateway实现脚本运行状态监控
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
python爬虫系列课程3:解决爬虫过程中遇到的编码问题
python爬虫系列课程3:解决爬虫过程中遇到的乱码问题 在爬取某些网站时,以4399小游戏网站为例,正常编写爬虫代码并执行之后会出现乱码,代码如下: import requestsheaders = {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko…...
ocr智能票据识别系统|自动化票据识别集成方案
在企业日常运营中,对大量票据实现数字化管理是一项耗时且容易出错的任务。随着技术的进步,OCR(光学字符识别)智能票据识别系统的出现为企业提供了一个高效、准确的解决方案,不仅简化了财务流程,还大幅提升了…...
Go入门之map
map类型是引用类型,必须初始化才能使用,为key-value形式 var userinfo make(map[string]string)userinfo["username"] "zhangsan"var user map[string]string{"username": "张三","age": &qu…...
SpringBoot 中封装 Cors 自动配置
在现代 Web 开发中,跨域资源共享(CORS)是一个常见的问题。Spring Boot 提供了灵活的方式来处理 CORS 配置。本文将介绍如何通过自动配置的方式,在 Spring Boot 应用程序中全局配置 CORS。 背景 当浏览器从一个域名的网页去请求另…...
Github很慢/无法访问:简单两步搞定
第一步:获取github当前的DNS列表 第二步:把它们复制到自己本地的hosts文件中,保存 比大象装冰箱还少一步!( 下面具体说怎么操作 ~) 获取github当前的DNS列表 http://raw.hellogithub.com/hosts 把这个地址粘贴到浏…...
反射机制的简单示例
一个使用反射机制的简单示例,这个示例将展示如何使用反射来实现一个通用的数据导出功能。 首先,让我们创建必要的项目结构和文件: 首先修改 pom.xml 添加依赖: <?xml version"1.0" encoding"UTF-8"?&…...
DeepSeek在学术读写翻译中的独特优势
上下文理解能力 DeepSeek的核心优势之一在于其卓越的上下文理解能力。它能够根据前文内容准确理解和回应用户的提问或指令,确保对话的连贯性和相关性。这一能力在处理长篇对话和复杂文本时尤为重要,能够帮助用户更好地把握整体逻辑和细节。 2. 翻译专业…...
rust笔记4-属性derive
在 Rust 中,#[derive] 是一种属性(attribute),用于自动为类型实现某些 Trait。通过 #[derive],编译器可以自动生成这些 Trait 的默认实现,从而减少手动编写重复代码的工作量。 #[derive] 通常用于实现一些常见的 Trait,例如: Debug:为类型生成格式化输出的代码。Clon…...
前端(AJAX)学习笔记(CLASS 2):图书管理案例以及图片上传
* BootStrap弹框 功能:不离开当前页面,显示单独内容,供用户操作 步骤: 1、引入bootstrap.css和bootstrap.js 2、准备弹框标签,确认结构 3、通过自定义属性,控制弹框的显示和隐藏 其中的bootstrap.css…...
跟李沐学AI:InstructGPT论文精读(SFT、RLHF)
原论文:[2203.02155] Training language models to follow instructions with human feedback 原视频:InstructGPT 论文精读【论文精读48】_哔哩哔哩_bilibili 简介 1. RLHF 的基本概念 RLHF 是一种结合强化学习和人类反馈的训练方法,旨在…...
RedisTemplate存储含有特殊字符解决
ERROR信息: 案发时间: 2025-02-18 01:01 案发现场: UserServiceImpl.java 嫌疑人: stringRedisTemplate.opsForValue().set(SystemConstants.LOGIN_CODE_PREFIX phone, code, Duration.ofMinutes(3L)); // 3分钟过期作案动机: stringRedisTemplate继承了Redistemplate 使用的…...
燧光 XimmerseMR SDK接入Unity
官网SDK文档连接: RhinoX Unity XR SDK 一:下载SDK 下载链接:RhinoX Unity XR SDK 二:打开Unity项目,添加Package 1、先添加XR Core Utilties包和XR Interaction Toolkit包 2、导 2、再导入下载好的燧光SDK 三&…...
Mycat中间件
一、概述 Mycat是开源的,活跃的、基于java语言编写的MySQL数据库中间件。可以像使用MySQL一样使用mycat,对于开发人员来说根本感觉不到mycat的存在; 二、安装 Mycat是采用java语言开发的开源数据库中间件,支持windows和linux运行环…...
【HBase】HBaseJMX 接口监控信息实现钉钉告警
目录 一、JMX 简介 二、JMX监控信息钉钉告警实现 一、JMX 简介 官网:Apache HBase ™ Reference Guide JMX (Java管理扩展)提供了内置的工具,使您能够监视和管理Java VM。要启用远程系统的监视和管理,需要在启动Java…...
OpenLayers总结3
一、 静态测距 1.原理 静态测距主要是针对地图上已有的矢量要素(如线要素),利用 OpenLayers 提供的几何计算函数来获取其长度。在实际操作中,先加载包含几何要素的 GeoJSON 数据到矢量图层,当鼠标指针移动到要素上时…...
【OpenCV】在Liunx中配置OpenCV环境变量
将 /usr/local/include/opencv4 加入到环境变量中,可以帮助编译器找到 OpenCV 的头文件。这可以通过设置 CPLUS_INCLUDE_PATH 和 C_INCLUDE_PATH 环境变量来实现。以下是具体步骤: 方法一:临时设置环境变量 如果您希望临时设置这些环境变量…...
游戏引擎学习第109天
回顾目前进展 在这一期中,讨论了游戏开发中的一个重要问题——如何处理Z轴值的表示,尤其是在一个3D游戏中,如何更好地表示和存储这些值。上次的进展中,已经解决了透视投影的问题,意味着渲染部分的Z轴代码基本上已经完…...
npm、yarn、pnpm 的异同及为何推荐 pnpm
文章目录 一、引言二、npm 介绍(一)工作原理和特点(二)优势与不足 三、yarn 介绍(一)诞生背景和特性(二)与 npm 的主要区别 四、pnpm 介绍(一)核心优势和创新…...
基于遗传算法排课系统
一、遗传算法介绍: 遗传算法核心的任务是要通过编码体系,给出解决方案的染色体表现规则,首先需要随机初始化一定数量的种群(population),而种群则由一定数目的个体(individual)构成。每个个体实际上是染色体…...
Windows 图形显示驱动开发-GpuMmu 示例方案
本文介绍常见使用方案以及实现这些方案所需的操作顺序。 更新进程的页表条目 下面是更新页表条目以将属于进程 (P) 的分配映射到物理内存的操作序列。 假定页表分配已驻留在图形处理单元中GPU)内存段。 视频内存管理器在分页进程上下文中为进程 P 的根页表分配分配虚拟地址范…...
【Linux AnolisOS】关于Docker的一系列问题。尤其是拉取东西时的网络问题,镜像源问题。
AnolisOS 8中使用Docker部署(全)_anolis安装docker-CSDN博客 从在虚拟机安装龙蜥到安装docker上面这篇文章写的很清晰了,我重点讲述我解决文章里面问题一些的方法。 问题1: docker: Get https://registry-1.docker.io/v2/: net/h…...
策略+适配器模式详解
文章目录 1.策略模式1.目录结构2.Strategy.java 策略接口3.StrategyA.java 策略A4.StrategyB.java 策略B5.StrategyC.java 策略C6.Context.java 策略上下文7.Client.java 客户端8.小结 2.适配器模式1.目录结构2.CustomPaymentProcessor.java 自己的支付接口3.PayPalPaymentServ…...
Vue中事件名的命名规范
Vue中事件名的命名规范 起因: 本人之前不太写vue的项目,最近接触了vue的代码,在学习的过程中同时也会伴随着一点疑惑。比如一以下面的父子组件的事件传递为例: 父组件: 显然,父组件有个自定义事件refre…...
云计算架构学习之Ansible-playbook实战、Ansible-流程控制、Ansible-字典循环-roles角色
一、Ansible-playbook实战 1.Ansible-playbook安装软件 bash #编写yml [rootansible ansible]# cat wget.yml - hosts: backup tasks: - name: Install wget yum: name: wget state: present #检查playbook的语法 [rootansible ansible]…...
背包dp与数位dp
背包dp 介绍 动态规划实际上就是将复杂问题分解成若干个子问题,并通过子问题的解逐步发展成整体问题的解的算法思想。(我感觉这个解释就跟递归的思想一样) 背包问题分为01背包(物体只能使用一次),完全背包(物体可以使用无数次)&…...
【linux】更换ollama的deepseek模型默认安装路径
【linux】更换ollama的deepseek模型默认安装路径 文章目录 【linux】更换ollama的deepseek模型默认安装路径Ollama 默认安装路径及模型存储路径迁移ollama模型到新的路径1.创建新的模型存储目录2.停止ollama3.迁移现有模型4.修改 Ollama 服务配置5.重启ollama6.验证迁移是否成功…...
【紫光同创国产FPGA教程】——FPGA开发工具使用
本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com) 一:实验简介 实验目的:了解PDS软件的使用,在线Debugger工具的使用请看第八章uart实…...
面试技术分享:MySQL死锁与事务等待超时的临时解决方案
📝 面试技术分享:MySQL死锁与事务等待超时的临时解决方案 1. 问题背景 某电商系统在促销高峰期出现库存更新失败,日志报错: Lock wait timeout exceeded; try restarting transaction (errno 1213)现象:多个事务因争…...
6.3 k8s的事件event和kube-scheduler中的事件广播器
什么是k8s的events k8s的events是向您展示集群内部发生的事情的对象 例如调度程序做出了哪些决定或者为什么某些 Pod 从节点中被逐出 哪些组件可以产生events 所有核心组件和扩展(操作符)都可以通过 API Server 创建事件k8s 多个组件均会产生 event …...
OAI 平台 4G(LTE)基站 、终端、核心网 端到端部署实践(一)
本系列文章,基于OAI LTE代码搭建端到端运行环境,包含 eNB,EPC,UE三个网元。本小节先介绍系统总体架构,硬件平台及驱动安装方法。 1. Overview 系统总体架构如下图所示。 2 Machine setup 2.1 Machine specs Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS…...
t113修改串口
1 sys_config.fex [uart_para] uart_debug_port 0 uart_debug_tx port:PE02<6><1><default><default> uart_debug_rx port:PE03<6><1><default><default> 2 uboot修改启动参数 3 修改env.cfg启动地址和传输 #ear…...
「软件设计模式」桥接模式(Bridge Pattern)
深入解析桥接模式:解耦抽象与实现的艺术 一、模式思想:正交维度的优雅解耦 桥接模式(Bridge Pattern)通过分离抽象(Abstraction)与实现(Implementation),使二者可以独立…...
“地质环境体检”辅助智慧地质,服务工程建设、城市用地规划
随着社会经济的高速发展,各类工程建设也在加快筹建中。在工程项目的快速推进中,如何保障工作安全和工程建设的质量,是国家和社会普遍关注的一个问题。地质环境条件是影响工程建设、城市用地规划的重要因素,加强地质风险系统性研究…...
TMS320F28335二次bootloader在线IAP升级
F28335总共ABCDEFGH个区域,每个32K*16bits,即64K字节。 bootloader代码占用A区,地址0x338000~0x33FF7F,cmd文件中SECTIONS部分,需要添加Flash28_API相关信息,具体下载Flash28335_API_V210的demo࿰…...
java:用Guava的TypeToken优雅处理通配符类型(WildcardType): ? extends Number
在日常开发中我们经常会遇到泛型和通配符类型(WildcardType),比如当我们需要处理List<? extends Number>这样的类型时,如何优雅地创建这样的类型表示?本文将重点介绍如何通过Guava的TypeToken来实现通配符类型的…...
ROS-相机话题-获取图像-颜色目标识别与定位-目标跟随-人脸检测
文章目录 相机话题获取图像颜色目标识别与定位目标跟随人脸检测 相机话题 启动仿真 roslaunch wpr_simulation wpb_stage_robocup.launch rostopic hz /kinect2/qhd/image_color_rect/camera/image_raw:原始的、未经处理的图像数据。 /camera/image_rectÿ…...
Zabbix——Rocky9安装zabbix相关步骤记录
安装Zabbix 安装MariaDB 这里用MariaDB演示 https://mariadb.org/download/?trepo-config&dRedHatEnterpriseLinux9&v10.11&r_mneusoft 通过这个网址获得连接 选择对应的repo 根据系统版本和要安装的版本选择对应的repo 安装 新建一个repo文件,例…...
三轴云台之姿态测量篇
一、姿态测量的基本原理 三轴云台通过内置的传感器实时感知其姿态变化。这些传感器主要包括陀螺仪、加速度计和磁力计(在某些高级系统中)。 陀螺仪:用于检测云台的角速度变化,即绕三个轴的旋转速度。陀螺仪提供的数据是姿态测量的…...
Kotlin 2.1.0 入门教程(二十三)泛型、泛型约束、协变、逆变、不变
out(协变) out 关键字用于实现泛型的协变。协变意味着如果 B 是 A 的子类型,那么 Producer<B> 可以被视为 Producer<A> 的子类型。这里的 Producer 是一个使用泛型类型参数的类或接口,并且该泛型类型参数被标记为 ou…...
VSCode 中使用 Snippets 设置常用代码块
背景 在开发中,有很多代码片段是重复的,例如:vue文件中的模版,react 中的模版,打印的 log 等等,很多很多。对于这些重复性的工作,vscode 官方提供了解决方案-Snippets in Visual Studio Code&a…...
在conda虚拟环境中安装jupyter lab-----deepseek问答记录
在 Conda 虚拟环境中安装 Jupyter Lab 的步骤如下: 1. 创建并激活 Conda 虚拟环境 如果你还没有创建虚拟环境,可以使用以下命令创建一个新的虚拟环境并激活它: conda create -n myenv python3.x # 将 myenv 替换为你的环境名称࿰…...
单元测试整理
在国外软件开发中,单元测试必不可少,但是国内并不太重视这一块,一个好的单元测试可以提前发现很多问题,也减去和测试battle的时间 Spring单元测试 JUnit4 RunWith 指明单元测试框架 e.g. RunWith(SpringJUnit4ClassRunner.cla…...
计算机毕业设计hadoop+spark旅游景点推荐 旅游推荐系统 旅游可视化 旅游爬虫 景区客流量预测 旅游大数据 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Java虚拟机面试题:内存管理(下)
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...