最小树形图的环收缩

本文介绍了如何在有向图中处理最小生成树时遇到的环问题。通过将环视为一个点,并忽略环内的边,讨论了如何更新环外指向环的边的权重。在存在负权边的情况下,博客强调了朱刘算法确保选取的总是最短入度边,从而避免负值问题。举例说明了B、C两点构成的环如何进行权重更新,并解答了关于负权重的疑问。

气死我了,最近学习关于最小树形图的问题,无论是优快云还是博客园,真就是天下文章一大抄,图都用一模一样的,又复杂又高糊,我只是想搞懂存在环,这个环是怎么收缩的,结果给我看了屎一样图和文字表达。一气之下,写一个短文好还描述一下环是怎么收缩成点的。

本文只简述环的收缩


首先,要知道在有向图中,我们把有向图的最小生成树称作最小树形图

先看文字解释吧:

  1. 若有向图中有环,那么把这个环看成一个点,对于环内的边我们暂时忽略。
  2. 既然有环,那就是有回路,也就是环内每个点都有指向该点的边。
  3. 环外也有指向该环(或者说是收缩成了点)的边,如果没有指向该环的边,就不能构成最小树形图。
  4. 现在将环展看,关注环内的点。假设环内存在点VVV,对于VVV,一定在环内存在指向它的一条边E1E_1E1。假设现在环外也存在指向它的一条边E2E_2E2,那么我们将E2E_2E2进行更新。更新规则是:
    E2=E2−E1 E_2 = E_2-E_1 E2=E2E1

看图:
在这里插入图片描述
B、C构成环,节点B的入度为2,其中A-->B = 10C-->B = 5,所以更新A-->B = 10-5 = 5;同理,更新A-->C = 7 - 3 = 4


  • 有一个问题:如果A-->B < C-->B的话,那么减出来不就为负值了么?朱刘算法能解决负值么?
    能提出这个问题的同学,就是压根没理解朱刘算法。要知道我们判断环的条件是什么?不只是判断有没有回路,更重要的是,在这之前我们选取的边是最短入度边。就是说B的最短入度边是C传来的,C的最短入度边是B传来的,因此BC才能成环。所以其他点到B的权重一定大于C到B的权重。
### 关于有向图最小生成树 对于无向图,最小生成树是一个经典的优化问题,可以通过 Kruskal 或 Prim 算法来解决。然而,在有向图的情况下,定义和求解最小生成树会有所不同。 #### 定义 在有向图中,“最小生成树”的概念通常被扩展为 **最小生成森林** 或者更具体地说是 **最小强连通分支树 (Arborescence)**。一个 Arborescence 是一种特殊的有向生成树,其中所有的边都指向根节点或者从根节点出发[^3]。换句话说: - 如果存在一个指定的根节点 \( r \),那么该有向图的一个最小生成树可以看作是从这个根节点出发的一棵最小权值的树形结构。 这种情况下,我们称之为 **最小成本有向生成树 (Minimum Cost Directed Spanning Tree)** 或简称 **最小 Arborescence**。 #### Edmonds' Algorithm(Edmonds 算法) 针对有向图中的最小生成树问题,最著名的算法是由 Jack Edmonds 提出的一种贪心策略,称为 Edmonds’ algorithm。此算法能够有效地计算以某个特定顶点作为根节点的最小 Arborescence。以下是其核心思想: 1. 初始化:假设给定一个带权重的有向图 \( G=(V,E) \),以及选定的根节点 \( r \in V \)[^4]。 2. 构建候选集合:对于每一个非根节点 \( v \neq r \),选取进入 \( v \) 的具有最小权重的一条弧加入到当前候选集中。 3. 处理循:如果这些选出的弧形成了若干个独立回路,则通过收缩技术把这些回路压缩成单个超级节点,并重复上述过程直到不再形成新的回路为止。 4. 展开操作:最后一步是对之前所做的所有收缩动作逆序展开恢复原始图形并得到最终的结果。 这种方法的时间复杂度大约为 O(|E||V|),虽然不是最优效率级别,但在实际应用当中表现良好[^5]。 ```csharp // 下面给出的是伪代码框架用于说明逻辑流程而非完整的C#实现版本 public class Edge { public int From { get; set; } public int To { get; set; } public double Weight { get; set; } } List<Edge> FindMinSpanningArborescence(List<List<Edge>> graph, int root){ List<int>[] inverseGraph = BuildInverseGraph(graph); bool[] visitedNodes = new bool[graph.Count]; Array.Fill(visitedNodes, false); PriorityQueue<(int node, double cost),double> pq=new(); foreach(var edge in graph[root]){ pq.Enqueue((edge.To, edge.Weight), edge.Weight); } while(pq.TryDequeue(out var item)){ if(!visitedNodes[item.node]){ // Process the current minimum weight incoming arc... visitedNodes[item.node]=true; foreach(var outgoingEdge from graph[item.node]){ if(!visitedNodes[outgoingEdge.To]) UpdatePriorityQueueWithNewCosts(pq,outgoingEdge); } } } } ``` 上面展示了一个简化版的思路转换为程序设计形式的例子,注意这并非严格意义上的Edmond's Algorithm完全体,仅提供理解上的帮助[^6]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值