C++ 烟花算法

2025年3月24日 | 7分钟阅读

绽放算法 (Blossom Algorithm) 是 Jack Edmonds 于 1961 年首次提出的开创性组合优化算法。该算法通常用于解决任意图的最大匹配问题,其目标是找到一组最多的边,使得任意两条边都没有公共顶点。

图论中,匹配是一组边,其中任意一对边都具有不同的顶点。最大匹配是在图上可以找到的最大匹配。Hopcroft-Karp 算法用于找到二分图的最大匹配。但不幸的是,它不适用于一般图,尤其是包含奇数长度环的图;因此,像 Edmonds 的算法这样的其他方法比它更受欢迎。因此,绽放算法是匹配研究的主要算法之一。

绽放算法在网络设计、分配问题、作业调度和资源分配等实际应用中非常有用。

匹配概念

用数学术语来说,匹配被定义为图中的一组边,其中所有边都是顶点不相交的。例如,这些顶点:A、B、C、D 和边 (A,B)(A,B)、(C,D)(C,D) 将构成一个匹配,前提是 A 或 B 不与 C 或 D 相邻。当匹配在满足此条件的情况下拥有最多的边时,则称其为最大匹配。

绽放和增广路径

在图中,增广路径是指以未匹配顶点开头和结尾,并在匹配边和未匹配边之间交替的路径。如果存在这样一条路径,我们可以通过翻转路径上的边来增加匹配的大小。

通过诸如奇数长度环或图中的绽放之类的结构,我们可以与二分图不同地找到增广路径。正式来说,这些会使匹配过程复杂化。绽放算法通过将这些绽放“收缩”成单个顶点来工作,这使得算法能够降低其图的复杂度并继续其增广路径搜索。

绽放算法的步骤

以下是算法 Blossom 工作过程中需要遵循的高层解释:

  • 初始化:从空匹配 M=∅ 开始。
  • 查找增广路径:在当前图中搜索增广路径。如果找到,则通过翻转路径上的边来增加匹配的大小。
  • 检测绽放:在搜索增广路径时,如果找到绽放,则收缩此绽放成为一个顶点,并在修改后的、收缩的图上继续搜索。
  • 收缩图中的增广路径:如果在收缩的图中找到增广路径,在继续步骤 6.1 之前,将所谓的绽放恢复到其原始状态。展开图中的路径仍然是增广的,因此会根据需要更新匹配。
  • 重复:重复查找增广路径和收缩绽放的操作,直到找不到为止。
  • 终止:当找不到进一步的增广路径时,算法终止,当前匹配被认为是最大匹配。

绽放算法是如何工作的?

  1. 初始匹配
    算法从一个任意匹配(最初为空)开始,并通过搜索增广路径来迭代改进它。最初,所有顶点都被认为是未标记的。
  2. 交替树
    该算法构建交替树来探索图。交替树是指边在匹配或不匹配之间交替的树。增广路径的搜索从以未匹配顶点为根的树开始,以到达目标路径一端的另一个未匹配顶点。如果找到这条路径,那么匹配就会被增广。如果找到路径,那么匹配就会被增广。
  3. 搜索绽放
    如果在搜索增广路径时检测到奇数长度环,算法就会将其识别为绽放。当算法通过将整个环视为单个顶点并继续搜索增广路径来收缩其绽放时,就会出现这种情况。
  4. 展开绽放
    一旦发现了增广路径中的绽放,该绽放随后会被展开回其完整大小。

应用

绽放算法广泛应用于寻找最优配对或匹配至关重要的领域。

  • 网络设计:它优化通信网络的设计,这需要一种有效的配对资源或节点的方法。
  • 无冲突调度:绽放算法可以将任务与资源在不同的时间冲突中进行匹配,以最大化效率或最小化成本。
  • 运筹学:配对中的一般优化存储在操作的优化中。
  • 图论:它是图论中其他结果的基础,并有助于其他组合优化。
  • 市场出清:在这里,我们看到该算法在经济学中的应用,尤其是在市场出清问题中,其中买卖双方之间的最优匹配起着作用。
  • 生物学:生物信息学中使用绽放算法解决了与基因组测序和系统发育树构建相关的问题。

示例

让我们来看一个实现绽放算法的程序,使用 C++

输出

 
2 3
1 5
2 5
3 8
1 5   

说明

变量和数据结构

  • MAXN:顶点的最大数量,在本例的定义上下文中,其值为 500。
  • adjacent[MAXN]:图的邻接表表示,其中每个顶点被分配一个其邻居的列表。
  • matchValue[MAXN]:一个存储当前匹配的数组。如果 matchValue[i] 是 j,则表示顶点 i 与顶点 j 匹配。如果 matchValue[i] 是 -1,则表示顶点 i 未匹配。
  • visitedNodes[MAXN]:一个布尔数组,用于包含在 BFS 搜索增广路径过程中访问过的顶点。

FindAugmentPath 函数

  • 目标:以顶点 u1 为基础查找增广路径。
  • BFS 初始化:使用顶点 u1 启动一个队列,并将 visitedNodes[u1] 标记为 true。
  • BFS 循环运行:对于队列中找到的每个节点 v1,检查其邻居 w。

如果 w 未被访问且未匹配 (matchValue[w] == -1),则找到增广路径。返回 w。

否则,将 w 标记为已访问,并将匹配的顶点 matchValue[w] 加入队列。

  • 返回:如果没有找到增广路径,则返回 -1。

blossomAlgo 函数

  • 目的:实现绽放算法的主逻辑以查找最大匹配。
  • 初始化匹配:将所有 matchValue 条目设置为 -1(未匹配)。

遍历顶点:对于每个顶点 u

  • 如果 u 未匹配 (matchValue[u] == -1),则清除 visitedNodes 数组,并尝试使用 findAugmentPath(u) 从 u 开始查找增广路径。
  • 如果找到增广路径 (v != -1),则通过设置 matchValue[u] = v 和 matchValue[v] = u 来更新匹配。

输入

  • 读取顶点数 (number) 和边数 (m)。
  • 读取 m 条边,每条边连接两个顶点 u 和 v。将每条边添加到邻接表中。
  • 运行绽放算法:调用 blossomAlgo(number) 来查找最大匹配。
  • 输出:打印出匹配的对。对于每个顶点 i,如果已匹配(即 matchValue[i] != -1),则打印对 i 和 matchValue[i]。

绽放算法的优点

绽放算法的几个优点如下:

  • 绽放算法可以处理任何存在奇数环的图,而简单的算法只能处理二分图。
  • 时间复杂度为 O(V3),该算法对于许多实际应用来说足够高效。
  • 保证精确解:对于任何一般图,该算法都保证找到最大匹配。

结论

总而言之,绽放算法已成为一种有用的解决方案,用于查找任意图中的最大匹配,其用途超出了仅限于二分图的范围,而简单的算法可能在该领域失败。利用诸如增广路径和结构之类的概念的优势,该算法可以优雅地处理不规则图,从而即使在图中有一些奇数长度的环的情况下也能实现最大匹配。该算法在时间复杂度和较低复杂度之间取得了平衡,其 O(V^3) 的复杂度可提供最优解决方案,降低了成本效益。其广泛的应用包括网络设计、作业调度、资源分配以及图论的基础研究。总而言之,绽放算法连接了组合学的不同方面及其在实际中的应用。