算法设计与分析 作业三 答案与解析

本栏目内容由人工智能学院 星马梦缘、Inst Sec. (MHL)、Nan(ZN)、sssTNT(SCY)同学共同提供,感谢几位同学的辛勤付出!!!


题目一------单源最短路 考场标准时间15m

维护S Q表,Q按照从小到大的价值排序,每次选最小代价的点出来探索。

翻译:

在给定的带权有向图上运行Dijkstra算法,计算从顶点 a 出发的最短路径树(shortest-path tree)

具体要求:

在每一次迭代(循环)中,请展示以下四个中间结果:

  • (a) 从**优先队列(priority queue)**中选出的顶点;

  • (b) 每个顶点当前的最短距离估计值 dv

  • (c) 每个顶点的前驱节点 πv(即路径上的上一个节点);

  • (d) 已确定集合 S 的内容,以及剩余优先队列 Q 的内容。

最后:

画出或列出最终生成的最短路径树

涉及考点

Dijkstra 算法

简单来说,虽然"拓扑排序+松弛"在 DAG(有向无环图)中效率极高( O(V+E) ),但它有一个致命的**硬伤,**处理不了"环",而 Dijkstra 算法虽然慢一点( O((V+E)log⁡V)),却解决了这个硬伤。

1. 最大的问题:它处理不了"环"(通用性差)

这是最根本的原因。

  • 拓扑排序的前提 :图必须是无环的(DAG)。如果图中有环(比如 A->B->C->A),拓扑排序根本无法进行(找不到入度为0的节点),整个算法直接瘫痪。
  • 现实世界的图 :绝大多数现实生活中的图都是有环 的。
    • 地图导航:你可以从 A 走到 B,也可以从 B 走回 A(双向道路)。
    • 网络路由:数据包可以在网络中绕圈子。

Dijkstra 的优势 :它不依赖拓扑排序,它通过贪心策略(每次选当前距离最近的点)来处理节点。它完全不在乎图中有没有环,只要没有"负权环",它都能完美工作。

结论 :我们忍受 Dijkstra 稍微慢一点点(多一个 log⁡V ),是为了换取它能处理任意有环图的能力。

总结

算法 你的总结 核心关键词
Bellman-Ford 能解决负权边,有向/无向有环图 全能兜底
拓扑+松弛 解决有向无环图(无法解决循环依赖) 极速特化
Dijkstra 解决非负有环图 通用标准

解析

我的答案

维护S Q表,Q按照从小到大的价值排序,每次选最小代价的点出来探索。

zn同学的答案 交叉验证通过

题目二------多源最短路 考场标准时间40m

原理是由于DJ法无法处理负权边问题,因此引入一个"零势能面",将负权边转为正权边。

首先引入一个超级原点,就是零势能面,然后计算所有点到原点的最短路,用BellmanFOrd即可。

遍历所有变更新到无变化。

然后记录所有点到原点的最短路长度(相当于海拔高度有正有负),然后就能得到最低的海平面。

我们的任务就是以最低的海平面为0m。

因此引入变化势能函数尖w(A,B)=w(A,B)+h(A)-h(B)

这样算出来的新权重就是全为正的,可以用DJ法。

接下来就是用多源DJ法计算多源最短路,每次算出来一个点都要计算转换后的权重,也就是

σ(A,B)=δ(A,B)+h(B)-h(A),注意,这里是后减前,是为了还原到原始权重去计算!!!

这个σ就是最短路距离了!

翻译:用约翰逊算法解决多源最短路的问题

涉及考点

Johnson 算法(降低复杂度)

D法只适用于非负权边的图,因此对于有负权边的就必须对每个点跑一遍BF。

考虑将负权边变成非负的边,这样就能用D法了。

可是w(uv)可能是负的啊

总体思路:

将负权边转换为非负权边,引入势能函数,保证负权非负

1.引入超级原点S,将S与所有节点相连,权重为0

2.列出所有边

3.使用Bellmanford进行单元最短路计算,列边松弛列dΠ,得到S到各个点的最短路

4.计算势能 h(v)=δ(s,v)

5.计算等效边权w(u,v)_hat

6.这时就可以迪杰斯特拉了

最多需要遍历最短路径长度的边的轮数,每轮复杂度E

解析

我的答案

zn同学的答案 交叉验证通过

sssTNT同学的答案 交叉验证通过

题目三------找最短增广路 考场标准时间16m

翻译:

展示 Edmonds-Karp 算法在上述流量网络上的执行过程。请在每次迭代中,展示流量网络、残余网络、增广路径以及增加的流量(增量流)。最后,展示最大流量以及对应的最小割。

涉及考点

依赖于三个概念:

剩余网络:每条边还剩余多少流量

增广路:寻找可达路

cuts:如何将网络切割为两部分,限制流量上限

1. 剩余网络(Residual Network)

"这条路还能再走多少?"

  • 定义:在原网络的基础上,根据当前的流量情况,构建出一个"还能容纳多少新流量"的网络。
  • 核心指标:剩余容量(Residual Capacity)
    • 正向边:如果一条水管容量是 10,已经流了 3,那么剩余容量就是 10−3=710−3=7 。代表你还可以往里塞 7 个单位的流量。
    • 反向边(精髓所在) :这是 Ford-Fulkerson 算法最巧妙的地方。如果一条边已经流了 3 个单位的流量,算法会人为地增加一条反向边,其剩余容量为 3。
    • 为什么要有反向边? 它代表了**"反悔"**的能力。如果你后来发现之前流的这 3 个单位走错路了,可以通过反向边把这 3 个流量"退"回去,重新分配给其他路径。没有反向边,算法很容易陷入局部最优解。

2. 增广路径(Augmenting Path)

"找到一条能走通的路,并灌入流量。"

  • 定义 :在剩余网络中,从源点(Source)到汇点(Sink)的一条连通路径。只要这条路径上所有边的剩余容量都大于 0,它就是一条增广路径。
  • 瓶颈容量(Bottleneck Capacity) :一条路径能增加多少流量,取决于这条路上最窄的那根管子(即路径上剩余容量最小的那条边)。
  • 操作步骤
    1. 在剩余网络中找到一条增广路径。
    2. 找出该路径上的最小剩余容量(瓶颈)
    3. 沿着这条路径,正向边加上这个流量,反向边减去这个流量(更新剩余网络)。
    4. 重复上述过程,直到再也找不到增广路径为止。

3. 割(Cut)与最大流最小割定理

"流量的天花板在哪里?"

  • 定义:割是将网络中的所有顶点分成两个互不相交的集合:包含源点的集合 SS 和包含汇点的集合 TT 。
  • 割的容量:所有从 SS 指向 TT 的边的容量之和。你可以把它想象成把网络切成两半,切面上所有水管的总粗细。
  • 最大流最小割定理(Max-Flow Min-Cut Theorem) :这是 Ford-Fulkerson 算法正确性的数学基石。
    • 定理指出:一个网络的最大流量 = 该网络的最小割容量。
    • 直观理解:无论你中间的路网修得多么复杂,最终能流到终点的最大水量,一定受限于整个网络中最薄弱的那个"瓶颈截面"(最小割)。
    • 算法终止条件:当剩余网络中再也找不到增广路径时,说明源点和汇点在剩余网络中不连通了。此时,所有能从源点到达的点构成集合 SS ,其余点构成集合 TT 。这个 (S,T)(S,T) 割的容量恰好等于当前的流量,证明已经达到了理论上限(最大流)

第一行是正向边,减去流量

第二行是反向边,允许退还流量,加回去

同时表达正向容量和反向容量才是完整的当前状态。

计算残差网络

流增广

新流量 = 旧流量 + 正向推流 - 反向退流(要同时对正反边两个状态作出修改)

切割的流

EK法 找最短增广路

增广路径的选择会极大影响复杂度,因此需要一种快速方案

EK法,找最短的路径

算法流程

示例:

不在是在残差图中招任意一条最短路,而是构建一个GL层次图,在层次图里面找一条最短路

当当前的GL层次图没有到t的路径时,就重新在残差图中构建层次图

原图只带几比几、残图有双向边、层图有通也有断

算法复杂度:

解析

我的答案

zn同学的答案 交叉验证通过

题目四------线性规划问题 考场标准时间25m

翻译:

给定以下线性规划问题 (LP),

最大化 z=x1+2x2

约束条件 (s.t.):

x2≤2x1+2

x1+3x2≤27

x1+x2≤15

2x1≤x2+18

x≥0

通过几何论证和单纯形法计算其最优解。

涉及考点

线性规划

常见定义

矩阵化表达

有m个约束 n个变量。

要标准化转为线性约束标准问题

要求:所有x大于0 Σax<=b max问题

要把min变成max

要把=改为<=

要把所有的x约束大于0

1 将min改为max问题

2 将等式变为两个不等式夹击

3 并通过同乘符号把大于等于>=改为小于等于<=

4 补充限制条件

将自由变量变为两个非负变量的差

要求xj xj都大于0,这样就可以表示任意的实数

算法希望处理等式约束。

松弛形式

1 引入松弛变量 将不等约束改为等号约束

s定义为冗余量,即满足条件的剩余空间

Ax<=b => Ax+s=b

引入松弛变元------冗余量

引入后变量的总数会等于 不等号*2+等号 约束条件

basic nonbasic变量

约束等号左侧的变量x4 x5 x6是basic变量

x1 x2 x3是等号右边的,是nonbasic变量

2 将目标函数max也改为等号形式

将目标函数和下面的约束改为了等式。

这样等号左侧都是basic变量,右侧都是nonbasic变量。

(因为要分离BN变量,因此必须做将等号拆为不等式,再引入松弛变量转为等式的过程)

这样就可以转为矩阵形式运算。

A约束矩阵 b常数项 c目标项

如何解决LP问题------SImplex算法

初始化时所有NB变量都为0,此时可以计算出B变量的值 和 z的值

为了让Z最大,因此要增加x1 x2 x3

从三个NB变量中选一个,从零增加

这里选择x1

分别带入三个约束式子,看看在满足大于零1约束下要多少。

选择最少的x1.

x1《=9

然后把x1当作NB变量,把x6(交换过来的式子的NB变量)放到右侧(交换NB)

然后修改目标函数和约束条件(x1变为NB x6变为B变量)

然后基于这个新问题继续做

增加x2或x3,这里增加x2

选择x3更新

更新x2,由于x4=x2,因此增加x2不会导致x4的约束被破坏。

当更新到z的式子后面的参数都是负号时,说明增加谁都无法增加z了,停止更新。

算法流程

STF+RLF

初始0,选正参。(初始化所有的参数,N参数为自己,B为0;对于z=+-+-中+的参数更新)

最小正满足(在满足N变量大于0的情况下,计算让B最小的条件)

交换NB(代入式)(根据这个约束行,计算B=xxxxN,交换NB;并带入其他涉及B的约束式)

更新所有的代入处(更新z后,看z=后面是否全负,全负停止)

解析

流程参考下面:

先进行STF和RLF验证,符合形式后再进行求解即可。

我的答案

zn同学的答案 交叉验证通过 感谢多次指正!

题目五------二分图匹配问题(匈牙利树算法) 考查标准时间12m

翻译:

涉及考点

匈牙利树算法

从左侧节点中找到一个未匹配的节点,以此生成多条augpath,要求终点是unmathced的,然后翻转,更新M={()()}(加一),

算法流程

M={}

从空集开始,从l1开始匹配,找augpath,也就是找未匹配的终点,r1 r2 r4都可以。

M={(l1,r1)}

从l2开始匹配,找augpath,也就是找未匹配的终点,r2 r3都可以。

M={(l1,r1),(l2,r1)}

从l3开始匹配,找augpath,也就是找未匹配的终点,r3 r4都可以。

M={(l1,r1),(l3,r1),(l1,r4)}

从l4开始匹配,找augpath,也就是找未匹配的终点,r3可以。

做小题怎么办

匈牙利算法既可以从空集(没有任何匹配边)开始,也可以从任意一个合法的初始匹配(只要这些边互不冲突)开始。无论你的起点是什么,只要按照算法逻辑不断寻找并反转增广路,最终都能达到最大匹配。

为什么可以从任意合法匹配开始?

这背后的根本原因依然是增广路定理(Berge 引理):一个匹配是最大匹配,当且仅当图中不存在任何增广路。

  • 殊途同归:算法的终点是由"图中是否还存在增广路"决定的,而不是由"起点"决定的。
  • 动态调整:如果你随机给定的初始匹配比较"笨拙"(占用了关键节点,导致后面的人没得选),匈牙利算法在后续为其他节点寻找增广路时,会通过递归回溯(也就是你提到的"匈牙利树"的生长过程)去尝试"腾位置"。如果当前占位的人能找到别的下家,他就会让出位置;如果实在腾不出来,算法才会放弃。这个过程会自动修正前期不合理的匹配,直到再也找不到增广路为止。

解析

我的答案

zn同学的答案 交叉验证通过

相关推荐
微风欲寻竹影1 小时前
Java数据结构——二叉树(Binary Tree)详解
java·数据结构·算法
想吃火锅10051 小时前
【leetcode】3.无重复字符的最长字串js版
算法·leetcode·职场和发展
smith成长之旅1 小时前
08 | Mem0 框架分析: BM25 的 Sigmoid 归一化
数据库·python·算法
dongf20191 小时前
R 语言随机森林算法
算法·随机森林·r语言
AZaLEan__1 小时前
图论:拓扑排序
算法·深度优先
悠仁さん1 小时前
数据结构 排序
数据结构·算法·排序算法
阿文的代码库1 小时前
机器学习之精确率和召回率的关系
人工智能·算法·机器学习
咸鱼翻身小阿橙1 小时前
高斯模糊降噪/磨皮算法降噪图像
前端·opencv·算法·webpack·c#
代码中介商1 小时前
数据结构进阶(五):最短路径——Dijkstra 与 Floyd 算法
数据结构·算法