动态规划实战:从背包问题到最大流,5个经典案例带你掌握核心思想

分治与动态规划实战:从Master Method到背包问题的算法精解 本文深入解析了分治算法与动态规划的核心思想与应用。通过Master Method快速分析递归复杂度,并以经典的0-1背包问题为例,详细阐述了动态规划的状态定义、转移方程及空间优化技巧。文章对比了两种算法的思维差异,并简要延伸至最大流最小割定理,帮助读者系统掌握算法设计与优化方法。 阅读详情

动态规划实战:从背包问题到最大流,5个经典案例带你掌握核心思想

算法学习路上,动态规划(Dynamic Programming, DP)常常是那个让人又爱又恨的“拦路虎”。它不像排序、查找那样直观,也不像贪心算法那样“短视”,它要求你具备一种将复杂问题拆解、并洞察其内在最优子结构的能力。很多初学者在面对状态定义和转移方程时感到无从下手,而面试官却总爱用它来考察候选人的逻辑思维和问题建模能力。

这篇文章,我将带你跳出枯燥的理论推导,通过五个层层递进的经典案例,从最基础的01背包问题,一路讲到图论中的最大流问题,用Python代码和可视化的填表过程,亲手拆解动态规划的核心思想。我的目标不是让你死记硬背几个模板,而是真正理解如何识别问题、定义状态、建立转移方程,最终将这种思维内化为解决复杂问题的直觉。

1. 基石:从01背包问题理解状态与选择

动态规划之所以强大,在于它能将指数级复杂度的暴力搜索,优化为多项式时间。这一切的起点,往往是一个看似简单的“选择”问题。01背包问题就是最经典的入门案例:给定一组物品,每个物品有重量 w[i] 和价值 v[i],以及一个容量为 W 的背包。每个物品只能选择放入(1)或不放入(0),目标是让背包中物品的总价值最大,且总重量不超过 W。

为什么暴力搜索不行? 对于 n 个物品,每个物品有2种选择,总共有 2^n 种组合。当 n=30 时,组合数已超过10亿,计算量不可接受。

动态规划的破局思路:我们不直接枚举所有组合,而是思考“当背包容量为 j 时,考虑前 i 个物品,能获得的最大价值是多少?” 这定义了一个二维状态 dp[i][j]。

  • 状态定义:dp[i][j] 表示考虑前 i 个物品,在背包容量为 j 的情况下,能获得的最大价值。
  • 状态转移:对于第 i 个物品,我们只有两种选择:
    1. 不放入背包:那么最大价值就是考虑前 i-1 个物品、容量 j 时的最大价值,即 dp[i][j] = dp[i-1][j]。
    2. 放入背包:前提是当前背包容量 j 能装下它(j >= w[i])。如果放入,那么背包剩余容量为 j - w[i],我们需要在前 i-1 个物品中寻找这个剩余容量下的最大价值,然后加上当前物品的价值。即 dp[i][j] = dp[i-1][j - w[i]] + v[i]。 最终,dp[i][j] 取这两种选择中的最大值。

核心转移方程:

if j >= w[i]:
    dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i])
else:
    dp[i][j] = dp[i-1][j]

可视化填表过程:假设物品重量 w = [2, 1, 3],价值 v = [4, 2, 5],背包容量 W = 5。我们构建一个 (n+1) x (W+1) 的表格,第一行和第一列初始化为0(表示没有物品或容量为0时,价值为0)。

i\j012345
0000000
1 (2,4)004444
2 (1,2)024666
3 (3,5)024679

提示:填表时,dp[2][3] 的计算过程是:容量3,考虑前2个物品。选择1:不拿物品2,价值为 dp[1][3]=4;选择2:拿物品2(重量1),则剩余容量2看 dp[1][2]=4,总价值 4+2=6。取最大值6。

通过填表,我们避免了重复计算子问题(例如 dp[1][2] 被多次用到),最终 dp[3][5] = 9 就是答案。这个过程清晰地展示了最优子结构(当前最优解依赖于子问题最优解)和重叠子问题(多个状态会用到相同的子问题解)。

2. 序列型DP:编辑距离与状态设计的艺术

动态规划不仅适用于“选择”问题,更擅长处理序列或字符串的变换问题。编辑距离(Levenshtein Distance)问题是这类问题的代表:给定两个单词 word1 和 word2,计算将 word1 转换成 word2 所需的最少操作次数。允许的操作有:插入一个字符、删除一个字符、替换一个字符。

这个问题难在操作可以发生在序列的任何位置,且相互影响。暴力尝试所有编辑序列同样是指数级的。

状态设计的巧妙之处:我们不再关注整个字符串如何一步步变换,而是聚焦于前缀子串。定义 dp[i][j] 为将 word1 的前 i 个字符转换成 word2 的前 j 个字符所需的最少操作数。

  • 状态转移:考虑如何从更小的子问题得到 dp[i][j]。
    1. 如果 word1[i-1] == word2[j-1](注意下标偏移),那么最后一个字符相同,不需要操作,dp[i][j] = dp[i-1][j-1]。
    2. 如果最后一个字符不同,我们有三种操作选择,取其中代价最小的:
      • 替换:将 word1[i-1] 替换为 word2[j-1],代价为1,然后处理前 i-1 和 j-1 个字符,即 dp[i][j] = dp[i-1][j-1] + 1。
      • 删除:删除 word1[i-1],然后处理前 i-1 和 j 个字符,即 dp[i][j] = dp[i-1][j] + 1。
      • 插入:在 word1 末尾插入 word2[j-1],这等价于 word2 的第 j 个字符被匹配了,接下来处理 word1 的前 i 个字符和 word2 的前 j-1 个字符,即 dp[i][j] = dp[i][j-1] + 1。

核心转移方程:

if word1[i-1] == word2[j-1]:
    dp[i][j] = dp[i-1][j-1]
else:
    dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1

边界条件:dp[i][0] = i(将 i 个字符全部删除),dp[0][j] = j(插入 j 个字符)。

让我们以 word1 = "horse", word2 = "ros" 为例,看看填表过程(部分):

dp''ros
''0123
h1123
o2212
r3222
s4332
e5443

注意:计算 dp[1][1](‘h’ -> ‘r’):字符不同,min(dp[0][0], dp[0][1], dp[1][0]) + 1 = min(0,1,1)+1 = 1,对应一次替换操作。最终 dp[5][3] = 3 是最小编辑距离(horse -> ros:删除‘h’,替换‘r’为‘o’,删除‘e’)。

编辑距离问题展示了如何将复杂的序列操作,转化为对前缀子串的状态定义,并通过比较末尾字符,自然地推导出状态转移。这种“前缀子串”的思想,是解决最长公共子序列(LCS)、最长递增子序列(LIS)等问题的通用钥匙。

3. 区间型DP:矩阵链乘法的决策与代价

有些问题的最优解,依赖于对问题规模的一种“划分”。矩阵链乘法问题就是一个典型:给定一系列矩阵 <A1, A2, ..., An>,其中矩阵 Ai 的维度是 p[i-1] x p[i]。我们要计算它们的连续乘积 A1 * A2 * ... * An。由于矩阵乘法满足结合律,不同的计算顺序(加括号方式)会导致巨大的计算量差异。我们的目标是找到一种加括号方案,使得进行乘法运算的总次数最少。

例如,三个矩阵 A(10x100), B(100x5), C(5x50):

  • (A*B)*C:先算 A*B 需要 10*100*5=5000 次标量乘法,得到 (10x5) 的矩阵,再与 C 乘需要 10*5*50=2500 次,总计 7500 次。
  • A*(B*C):先算 B*C 需要 100*5*50=25000 次,得到 (100x50) 的矩阵,再与 A 乘需要 10*100*50=50000 次,总计 75000 次。效率相差十倍!

状态定义:定义 dp[i][j] 为计算矩阵链 Ai...Aj(即从第 i 个到第 j 个矩阵)所需的最少标量乘法次数。

状态转移的关键:对于区间 [i, j],我们考虑在某个位置 k (i <= k < j) 将其“切一刀”,分成两个子链 Ai...Ak 和 A_{k+1}...Aj。先分别计算这两个子链的最小代价,再将它们的结果相乘。这次相乘的代价是 p[i-1] * p[k] * p[j](因为 Ai...Ak 的结果矩阵维度是 p[i-1] x p[k],A_{k+1}...Aj 的结果矩阵维度是 p[k] x p[j])。我们遍历所有可能的 k,取最小值。

核心转移方程:

for k in range(i, j):
    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j])

填表顺序:这是一个典型的区间DP,我们需要按区间长度从小到大的顺序填表。因为计算长区间 [i, j] 需要用到所有更短的子区间 [i, k] 和 [k+1, j]。

假设矩阵链维度数组 p = [30, 35, 15, 5, 10, 20, 25],表示有6个矩阵:A1(30x35), A2(35x15), A3(15x5), A4(5x10), A5(10x20), A6(20x25)。我们构建 dp 表(n=6),对角线 dp[i][i] = 0(单个矩阵无需乘法)。

i\j123456
1015750787593751187515125
2-026254375712510500
3--075025005375
4---010003500
5----05000
6-----0

计算示例:dp[1][3] 表示计算 A1*A2*A3 的最小代价。有两种划分:

  1. k=1: (A1)*(A2*A3) -> dp[1][1]+dp[2][3]+30*35*5 = 0+2625+5250 = 7875
  2. k=2: (A1*A2)*A3 -> dp[1][2]+dp[3][3]+30*15*5 = 15750+0+2250 = 18000 取最小值 7875。

最终 dp[1][6] = 15125 就是全局最优解。为了回溯得到具体的加括号方式,我们可以在状态转移时记录下取得最小值的 k。矩阵链乘法问题教会我们,当问题的最优解依赖于对序列的某种划分时,区间DP是强有力的工具。

4. 树形DP:没有上司的舞会——从线性到非线性

动态规划并非只能处理线性序列或网格。当问题结构是一棵树时,我们同样可以应用DP思想,这被称为树形DP。经典问题“没有上司的舞会”(UVA 1220)描述了这样一个场景:公司要举办派对,员工关系呈树状结构。每个员工有一个快乐指数。规定直接上司和下属不能同时参加。求受邀员工的快乐指数之和的最大值。

这棵树中,每个节点(员工)有两种状态:参加或不参加派对。其状态会影响其子节点(下属)的状态。

状态定义:对于以节点 u 为根的子树,定义两个状态:

  • dp[u][0]: u 不参加派对时,以 u 为根的子树能获得的最大快乐值。
  • dp[u][1]: u 参加派对时,以 u 为根的子树能获得的最大快乐值。

状态转移:这需要从叶子节点向根节点进行后序遍历(DFS)。

  • 如果 u 不参加 (dp[u][0]),那么它的每个子节点 v 可以参加也可以不参加,我们取最大值累加:dp[u][0] += sum( max(dp[v][0], dp[v][1]) for v in children(u) )。
  • 如果 u 参加 (dp[u][1]),那么它的所有子节点都不能参加:dp[u][1] = happy[u] + sum( dp[v][0] for v in children(u) )。

核心转移方程(伪代码):

def dfs(u):
    dp[u][0] = 0
    dp[u][1] = happy[u]
    for v in children[u]:
        dfs(v) # 先处理子节点
        dp[u][0] += max(dp[v][0], dp[v][1])
        dp[u][1] += dp[v][0]

一个简单的例子:假设树结构如下(节点编号即快乐值):

        1(5)
       /     \
     2(1)     3(10)
    /   \        \
  4(2)  5(3)     6(7)

我们从叶子节点开始计算:

  • 节点4: dp[4][0]=0, dp[4][1]=2
  • 节点5: dp[5][0]=0, dp[5][1]=3
  • 节点2: dp[2][0] = max(0,2)+max(0,3)=2+3=5, dp[2][1]=1+0+0=1
  • 节点6: dp[6][0]=0, dp[6][1]=7
  • 节点3: dp[3][0] = max(0,7)=7, dp[3][1]=10+0=10
  • 节点1: dp[1][0] = max(5,1)+max(7,10)=5+10=15, dp[1][1]=5+5+7=17

最终,以节点1为根的整棵树的最大快乐值为 max(dp[1][0], dp[1][1]) = max(15, 17) = 17。树形DP将线性DP的“阶段”概念,转化为树上的“子树”,通过DFS自底向上地传递和合并信息,解决了具有层次依赖关系的问题。

5. 图论中的DP思想:最大流问题的增广路径视角

动态规划的思想甚至可以延伸到图论领域。最大流问题(Maximum Flow)是网络流理论的核心:给定一个有向图,其中每条边有一个容量(Capacity),有一个源点(Source)和一个汇点(Sink)。问从源点到汇点,能通过这个网络输送的最大流量是多少?

Ford-Fulkerson 方法及其优化版本 Edmonds-Karp 算法(使用BFS寻找增广路径)是解决最大流问题的经典算法。虽然它通常不被归类为标准的动态规划算法,但其核心思想——反复寻找局部改进(增广路径)来逼近全局最优——与DP的“利用子问题解构建原问题解”的思想有异曲同工之妙。更重要的是,最大流最小割定理揭示了这个问题深层的结构。

算法核心:寻找增广路径

  1. 初始化:所有边的流量为0。
  2. 循环:在残量网络(Residual Network)中寻找一条从源点到汇点的路径(增广路径),该路径上所有边的剩余容量都大于0。
  3. 增广:找到这条路径上最小的剩余容量 min_cap,将路径上所有边的流量增加 min_cap,反向边的流量减少 min_cap(这为“反悔”提供了可能)。
  4. 更新残量网络:根据新的流量更新每条边的剩余容量(正向边容量减少,反向边容量增加)。
  5. 重复步骤2-4,直到找不到增广路径为止。此时的总流量即为最大流。

为什么需要反向边? 考虑一个简单的例子:源点s连接节点a和b,a和b都连接汇点t,边 (s,a), (a,t), (s,b), (b,t) 容量均为1。如果第一次找到路径 s->a->t,流量为1。没有反向边的话,算法就结束了,得到流量1。但实际上我们可以同时走 s->a->t 和 s->b->t,最大流是2。反向边 (a,s) 在 s->a 有流量后,其残量容量变为1,允许在后续寻找路径时“退回” s->a 的流量,改走 s->b->t,从而找到全局最优解。

用Python实现Edmonds-Karp算法:

from collections import deque

def edmonds_karp(graph, source, sink):
    """
    graph: 邻接表表示的残量网络,graph[u][v] = capacity
    返回最大流的值
    """
    n = len(graph)
    # 初始化流量矩阵和反向图
    flow = [[0] * n for _ in range(n)]
    parent = [-1] * n
    max_flow = 0

    def bfs():
        """BFS寻找一条从source到sink的增广路径,并返回可增加的流量"""
        visited = [False] * n
        visited[source] = True
        queue = deque([source])
        parent[:] = [-1] * n
        min_cap = [float('inf')] * n # 记录到达每个节点的路径上的最小容量

        while queue:
            u = queue.popleft()
            for v, cap in enumerate(graph[u]):
                if not visited[v] and cap > 0: # 有剩余容量且未访问
                    visited[v] = True
                    parent[v] = u
                    min_cap[v] = min(min_cap[u], cap)
                    if v == sink:
                        return min_cap[sink]
                    queue.append(v)
        return 0 # 未找到增广路径

    while True:
        augment = bfs()
        if augment == 0:
            break
        max_flow += augment
        # 沿着找到的路径更新残量网络
        v = sink
        while v != source:
            u = parent[v]
            graph[u][v] -= augment # 正向边减少容量
            graph[v][u] += augment # 反向边增加容量(允许反悔)
            v = u

    return max_flow

# 示例:构建一个简单的图
# 节点: 0(source), 1, 2, 3(sink)
n = 4
graph = [[0]*n for _ in range(n)]
graph[0][1] = 3
graph[0][2] = 2
graph[1][2] = 5
graph[1][3] = 2
graph[2][3] = 3

max_flow = edmonds_karp(graph, 0, 3)
print(f"最大流为: {max_flow}")

与动态规划思想的联系:每一次寻找增广路径并更新流量,可以看作是在当前“状态”(流量分布)下,做出一个局部最优的决策(沿着一条能增加总流量的路径推送流量)。算法保证了这个局部改进不会破坏最终解的最优性,并且通过反向边机制,它实际上探索了多种流量分配的组合,最终收敛到全局最优解。这类似于一种基于“状态”(当前流量)进行“决策”(选择哪条增广路径)的迭代优化过程。

最大流最小割定理:这个定理是最大流问题的理论基石。它指出,在一个流网络中,从源点到汇点的最大流量,等于将所有顶点划分成两个集合(一个包含源点S,一个包含汇点T)后,从S指向T的所有边的容量之和的最小值。这个最小值对应的边集合就是一个“最小割”。这个定理不仅证明了Ford-Fulkerson类算法的正确性,也揭示了最大流和最小割这两个看似不同问题的对偶关系。

从01背包的“选与不选”,到编辑距离的“字符变换”,再到矩阵乘法的“区间划分”,树形舞会的“依赖决策”,最后到最大流的“路径增广”,这五个案例覆盖了动态规划最常见的几种问题形态。它们的共同点在于,都将一个复杂问题分解为一系列重叠的子问题,并通过存储子问题的解来避免重复计算。真正的掌握,来自于亲手推导状态转移方程、画出填表过程、并敲出能运行的代码。下次当你遇到一个新问题时,不妨先问自己:这个问题的最优解,能否由其子问题的最优解构造出来?子问题之间是否有大量重叠?如果答案是肯定的,那么动态规划很可能就是你要找的那把钥匙。

掌握数据结构与算法动态规划的网络流与动态规划 动态规划和网络流是数据结构与算法领域中非常重要的两个概念。动态规划主要用于解决具有最优子结构和重叠子问题的优化问题,通过将原问题分解为相对简单的子问题,并保存子问题的解来避免重复计算,从而提高算法的效率。网络流则是图论中的一个重要分支,主要研究如何在一个网络中分配资源,以满足特定的流量需求,常见的应用包括最大流、最小费用最大流等问题。本文的目的是帮助读者深入理解动态规划和网络流的基本概念、算法原理,并通过实际案例掌握它们的应用。 阅读详情

相关推荐

图论算法精解:Dijkstra、Kruskal、最大流与匈牙利算法建模实战

图论是计算机科学中研究图结构及其性质的基础理论,它通过顶点和边来抽象表示实体间的关系。其核心原理在于将现实世界的网络、路径、匹配等问题转化为图模型,并运用特定算法求解。掌握图论具有重要的技术价值,它是解决最短路径、资源分配、网络优化等复杂问题的关键,广泛应用于物流配送、社交网络分析、任务调度等领域。本文聚焦于图论在数学建模中的核心应用,深入剖析Dijkstra最短路算法、Kruskal最小生成树算法、最大流标号法及匈牙利算法等经典模型,并结合**司守奎《数学建模算法与应用》** 中的典型习题,拆解其背后的*

weixin_30940783的博客 284

动态规划实战:从背包问题到最大流问题,5个经典案例带你掌握核心思想

本文通过5个经典案例,从0-1背包问题到最大流问题,系统讲解动态规划的核心思想与应用。文章深入辨析动态规划与分治法的区别,重点解析最优子结构与状态转移方程的构建,并涵盖LCS、矩阵链乘法及最小费用最大流等高级主题,帮助读者掌握算法精髓并灵活应用于实际问题解决。

g9h0i1的博客 415

RoboCom国赛战利品分配:从多背包问题到公平分配的算法实战

在算法竞赛和工程实践中,资源分配与调度是经典的核心问题,其本质是将有限的物品(资源)合理地分配给多个接收者(智能体),以优化特定目标。这类问题通常可抽象为多背包问题或其变种,其原理在于如何在满足容量、互斥等约束条件下,通过动态规划、贪心、二分搜索等算法,寻找最优或可行的分配方案。其技术价值在于高效解决物流配送、云计算任务调度、分布式负载均衡等实际场景中的资源优化难题。本文聚焦于RoboCom世界机器人开发者大赛中的“战利品分配”赛题,该题是上述原理的典型应用,要求在多机器人间公平分配战利品,核心挑战在于处理

weixin_30673611的博客 278

第五期:经典优化(下)—— 动态规划与图论网络

欢迎来到本系列的第五课!当一个决策问题可以被分解成一系列相互关联的阶段,或者当问题本身可以被抽象成一个由点和线构成的网络时,我们就需要一套全新的、更具结构性的优化工具。动态规划 (Dynamic Programming):学习这种“化整为零,记忆求解”的强大思想,并探讨其在背包、区域、树形等问题上的应用。贪心算法 (Greedy Algorithm):理解这种“目光短浅”却常常异常高效的算法的本质。图论算法 (Graph Theory)

dl999666的博客 1155

网易运筹优化算法工程师笔试复盘:从建模到求解的实战指南

运筹优化是工业与互联网领域解决复杂决策问题的核心方法论,其本质是将业务需求抽象为数学规划模型,并通过精确算法或启发式算法求解。线性规划、整数规划、图论与动态规划构成了这一领域的基石,Dijkstra最短路径、最大流、状态压缩DP等算法在路径规划、资源分配、生产排程等场景中发挥着关键作用。随着即时配送、智能仓储和广告投放等业务对决策效率要求的提升,具备建模与求解能力的运筹优化算法工程师成为大厂争抢的人才。网易提前批笔试正是围绕这些核心能力展开,重点考察候选人对经典模型的掌握、算法原理的理解以及将业务问题转化为

weixin_33843409的博客 310

算法期末备考:从分治、动态规划到图论的核心范式与实战解析

算法设计与分析是计算机科学的核心基础,它研究如何高效、系统地解决计算问题。其核心原理在于通过抽象建模,将复杂问题分解,并运用分治、动态规划、贪心、回溯、图论等经典范式设计解决方案。掌握这些算法思想的技术价值在于,能够显著提升解决实际工程问题的效率与质量,例如在数据处理、路径规划、资源调度等场景中实现性能优化。本文聚焦于算法期末备考,通过深度剖析一份高度仿真的模拟试卷,将上述核心范式的概念、原理与应用融入具体题目解析中,例如结合动态规划的状态定义与贪心算法的选择性质,帮助读者在贴近考试的真实场景下,完成从知识

cuyi7076的博客 494

OpenCV图像分割算法:优先队列、最大流与动态规划的工程实践

图像分割是计算机视觉中的基础任务,其核心是将数字图像划分为多个有意义的区域。从算法原理看,经典分割方法通常将问题转化为图论优化或空间划分问题,其中优先队列、最大流和动态规划等数据结构与算法发挥着关键作用。这些技术在工程实现中需要特别考虑计算效率和内存优化,例如OpenCV使用斐波那契堆实现优先队列来加速分水岭算法,将复杂度从O(nlogn)降至接近O(n)。在实际应用中,算法选择需权衡分割精度、实时性要求和硬件限制,传统算法因其高效性和可解释性,在实时系统、移动设备等场景仍具优势。通过分析OpenCV中gr

weixin_30394669的博客 1120

图与网络模型:从最短路径到网络流,数学建模核心算法解析

图论是描述事物间关系的基础数学模型,其核心在于将实体抽象为顶点,关系抽象为边。基于此原理,通过为边赋予权重、容量等属性,便形成了功能更强大的网络模型,用于刻画资源流动与系统优化。这一技术价值在于为复杂系统的分析与决策提供了通用框架。在工程实践中,最短路径算法(如Dijkstra、A*)解决最优路线规划,网络流模型(如最大流、最小费用流)则优化资源分配,二者均是解决交通物流、任务调度等实际问题的关键技术。本文聚焦于图与网络模型在数学建模中的应用,深入剖析了最短路径、网络流、最小生成树等核心算法及其变体,并结合

weixin_30522095的博客 427

最大费用最大流:从网络流到收益最大化的算法实战

网络流是图论中的核心概念,用于模拟资源在系统中的流动与分配。其基本原理是在一个有向图中,从源点到汇点输送流量,同时满足每条边的容量限制和节点的流量守恒。在工程实践中,网络流算法常被用于解决资源调度、路径规划等优化问题。当优化目标从最小化成本转变为最大化收益时,经典的最小费用最大流算法便衍生出其重要的变体——最大费用最大流。该技术通过巧妙的权值转换(如取反或线性变换),将收益最大化问题映射为标准的最小费用流模型,从而利用成熟的SPFA或Dijkstra算法高效求解。它在任务调度、物流规划、游戏数值设计等需要最

weixin_34072637的博客 689

2026年数学建模国赛高教社杯D题算法(62):最小费用最大流问题的高效算法及其在智慧物流调度中的应用

最小费用最大流问题是网络流理论中的核心优化模型,在交通规划、物流配送、通信网络等众多领域具有深远应用。本文系统研究了最小费用最大流问题的数学本质、经典算法与前沿进展,提出了一种融合势函数更新与动态平衡优化的改进型原始对偶算法(Improved Primal-Dual Algorithm with Dynamic Potential Adjustment, IPD-DPA)。该算法通过在残差网络中引入自适应势函数调节机制,有效减少了算法迭代过程中的标号修正次数,显著提升了增广路径搜索效率。

YOLO 20

构建Jetson AGX Xavier高精度时间同步网络:从GPS/PPS授时到PTP局域网分发

本文详细介绍了如何在Jetson AGX Xavier平台上构建高精度时间同步网络。通过GPS/PPS信号进行高精度授时,并利用NTP服务校准系统时钟,最终通过PTP协议在局域网内分发亚微秒级同步时间,为机器人、自动驾驶等多传感器融合系统提供统一的时间基准。

weixin_29191761的博客 275

RoboCom国赛R4/R5题解:状压DP与网络流算法实战精讲

在算法竞赛中,动态规划与图论是解决复杂优化问题的两大核心支柱。动态规划通过状态定义与转移方程,系统化地求解最优解,其高级应用如状态压缩DP,能有效处理集合状态组合问题。图论则通过节点与边的关系建模现实系统,网络流算法(如最大流、最小费用最大流)是解决资源分配、路径规划等约束优化问题的利器。这些技术的工程价值在于能将复杂的现实场景(如机器人路径规划、工厂调度)抽象为可计算的数学模型,从而找到最优或可行的解决方案。本文以RoboCom世界机器人开发者大赛国赛高阶题目为例,深入剖析如何将“机器人寻宝”问题建模为带

weixin_30861459的博客 443

UWB学习——day4

总的来说,BPM-BPSK调制方案是一种利用脉冲位置和相位来编码信息的高效数字调制技术,特别适用于UWB通信系统,以实现高速数据传输和频谱效率。这种方式将时间和相位综合使用,从而提高了数据传输的容量。总之,超外差结构是一种接收器设计,通过将不同频率的信号转换到一个共同的中间频率来提高信号选择性和抗干扰性。超外差结构是一种用于接收器的电子电路设计,它的目标是从无线信号中提取有用的信息,比如音频、数据或图像。该芯片的接收机是超外差结构,所谓超外差结构一种基于频率转换的接收器架构,旨在提高信号选择性和抗干扰性。

许帅的博客 2557

流量优化之道:Ford-Fulkerson 最大流算法

本文深入解析了网络流问题的经典算法Ford-Fulkerson,探讨其在带宽分配、交通优化等实际场景中的应用。文章首先介绍了网络流的基本概念和关键术语,包括残量网络、增广路径和割的定义。通过图解详细阐述了Ford-Fulkerson算法的核心思想——通过不断寻找增广路径来增加流量,直至达到最大流。文中还揭示了最大流最小割定理的深刻内涵,并提供了算法的数据结构设计和Python实现代码。该算法为解决各类容量受限的网络优化问题提供了理论基础和实用工具。

lcreek的博客 371

无人机芯片模块技术要点分析

恶劣环境下信号稳定性:无人机在恶劣环境下工作时,遥感系统采集的信号往往很不稳定,视频信号处理芯片需要具备强抗干扰能力,能辨别脉冲脉宽为50ns以上、幅度为0V~4.5V的输入信号。这种架构能兼顾强大的运算能力和灵活的接口控制。芯片小型化:麻省理工学院的研究人员已设计出仅20平方毫米的微型芯片,可处理无人机飞行所需的惯性数据和相机图像,为微型无人机的发展奠定了基础。光子集成芯片(PIC) :研究显示,与电子芯片相比,光子计算芯片在延迟、计算容量和能效上都有数量级的提升,有望解决当前无人机系统的计算瓶颈。

YUNZHUO666的博客 1408

从量子兔AlphaPi硬件拆解到ESP32-C3库开发实战

本文详细拆解了量子兔AlphaPi开发板的硬件构成,重点分析了其核心ESP32-C3芯片及外围传感器。通过逆向工程揭示了GPIO引脚定义与通信协议,并实战演示了如何从零开发MicroPython库,驱动按键、加速度计及LED点阵,最终整合成一个互动平衡球游戏项目,展现了开源硬件在教育与二次开发中的潜力。

weixin_29164497的博客 460

Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量

本文介绍基于动态规划的最短路径算法,包括Bellman-Ford、SPFA和Floyd-Warshall算法。重点讲解Bellman-Ford算法的核心思想、实现细节和优化方法,通过实例演示如何处理含负权边的网络路径问题。文章还对比了动态规划与贪心策略的区别,说明动态规划在处理负权边时的优势。最后给出完整的Python代码实现,包括路径重构和负权环检测功能。

lcreek的博客 456

论文分享 - OctoMap八叉树建图原理

论文:OctoMap:An Efficient Probabilistic 3D Mapping Framework Based on Octrees。

一只废佐_的博客 2541

2022小米秋招算法笔试解析:动态规划、KMP与快速幂实战

在软件开发岗位的求职过程中,算法笔试往往是第一道重要关卡。无论是大厂还是互联网公司,笔试题型通常围绕数据结构与算法基础展开,高频考点包括数组、链表、二叉树、动态规划、贪心、字符串匹配等经典内容。其中,动态规划的状态设计能力、KMP算法中next数组的理解,以及快速幂对大数据场景的优化处理,都是决定能否稳定拿分的关键。这类题目不只考察知识点记忆,更注重工程实践中的边界处理、复杂度和代码稳定性。面试者需要掌握从读题、推导到AC的完整链路,并通过多维度的实战经验规避常见报错。通过对热门真题的复盘,可清晰把握笔试难

weixin_30697239的博客 347

【GNSS/Linux】BKG Ntrip Client (BNC) 的编译与安装

【GNSS/Linux】BKG Ntrip Client (BNC) 的编译与安装 1. BNC软件 1.1 软件介绍 The BKG Ntrip Client (BNC) is an Open Source multi-stream client program designed for a variety of real-time GNSS applications. It was primarily designed for receiving data streams from any Ntrip

小马甲的新马甲 7809

CMOS传输门实战:如何用模拟开关优化你的电路设计(附常见问题排查)

本文深入探讨了CMOS传输门在电路设计中的实战应用与优化策略。文章从核心参数选型入手,详细分析了导通电阻、电荷注入等关键特性对电路性能的影响,并提供了多路复用器构建、精密电路应用等实战架构。同时,重点分享了PCB布局、电源去耦的工程细节,以及开关不导通、信号失真、高频性能不足等常见问题的系统性排查指南,旨在帮助硬件工程师充分发挥CMOS模拟开关的效能,提升电路设计的可靠性与精度。

js777的博客 451

动态规划核心

源自知乎“如何理解动态编程”。 答得太美,故转之以收藏。 牛岱 写代码的,偶尔写歌。 1,786 人赞同了该回答 我觉得大部分高赞答案把简单的概念搞复杂了。 quora上有这样一个问题: How should I explain dynamic programming to a 4-year-old? 底下有个42K赞同的答案,是这样说的: *writes down "1+1+1+1+1+1+1+1 =" on a sheet of paper* ...

s_156的博客 436

NPU性能榨取手把手教程:RK3588上YOLOv5s多线程部署与120FPS极限探索

RK3588 YOLOv5s多线程部署优化指南 本教程深入解析RK3588芯片上YOLOv5s模型的高性能多线程部署方案。RK3588作为瑞芯微旗舰AIoT芯片,内置三核NPU(6TOPS算力)和硬件加速器(RGA/VPU),为AI推理提供强大支持。通过线程池技术,我们将视频处理的读取、推理、后处理等环节解耦并行,显著提升系统吞吐量。教程详细介绍了从PyTorch到RKNN格式的模型转换流程、INT8量化方法,以及基于RKNN C++ SDK的YOLOv5推理核心实现,帮助开发者最大化发挥RK3588的AI

LXY_LOVE36的博客 974

图论在数学建模中的核心应用:从算法原理到实战解析

图论作为描述事物间关系的数学语言,是计算机科学和复杂系统建模的基石。其核心原理在于将实体抽象为顶点,关系抽象为边,从而将现实世界的网络、路径、连通等问题转化为可计算的数学模型。这一技术价值在于提供了强大的算法工具箱,如用于最优寻路的Dijkstra算法、用于经济连接的Prim和Kruskal算法,以及用于资源传输极限分析的最大流算法。这些算法在工程实践中广泛应用于社交网络分析、交通物流规划、芯片设计等场景。本文聚焦于数学建模竞赛,深入探讨如何将物流配送、舆情传播等实际问题,通过图论模型进行抽象与求解,并解析

weixin_34417200的博客 791

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

星环科技算法岗笔试复盘:字符串匹配与动态规划全解析

在计算机算法体系中,字符串匹配与动态规划是两大基石。KMP算法通过next数组避免重复匹配,堆排序则依靠建堆与下调实现高效排序,这些经典数据结构原理不仅服务于单机场景,更在分布式计算中延伸出关键路径、任务调度等模型。理解这些技术价值,能帮助开发者应对数据倾斜、Top-N统计等真实工程挑战。本文以星环科技秋招算法岗笔试为样本,还原了字符串哈希变体、带权区间调度、拓扑排序与DP结合等题目,剖析解题思路与优化方案,并复盘大数据场景设计题的作答策略,为备战大厂算法岗提供可落地的复习方向。

weixin_34151004的博客 365

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: uniapp文件分享到微信全攻略:从插件配置到打包上线的完整流程
下一篇: 为什么你的CNN模型效果差?可能是卷积核参数没调对:详解3×3/5×5卷积选择策略
lambda
博客等级 码龄23年 49粉丝 1303原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值