求最小生成树的新算法

不管 prim 算法还是 kruskal 算法都基于 “当前可见最短边” 作贪心策略,但这并不适合分布式并行操作,比方说所有节点一起构建最小生成树,这些算法都显得同步开销过大,甚至导出错误的结果。

最近研究并构建最大流多路径传输协议的模型,也懒得翻书,在早上冒大雨跑步时思考,后来发现 STP(Spanning Tree Protocol) 大致上(并非完全一致)也是这思路。分布式环境下必须要并行操作,而这需要一个新路子。

先说基础,连通图中环路上的最大边一定不在最小生成树中。这很容易用反证法证明:
在这里插入图片描述

这也是个自由度问题,因为事情必须这样,不这样就会有不可能的结果。反之,“一个环的最小边一定在最小生成树中” 却不正确。

环最小边不一定在最小生成树,双环叠加时,同一边可以同时最小和最大正负对冲,不能同时保留,但最大边一定不在最小生成树,同时将它们都砍掉可正正叠加,越砍权重越小:
在这里插入图片描述

基于此,只要找到一个环,砍掉它的最大边,砍掉所有环最大边后,事情就成了。

和最短路径树用广度优先遍历策略不同,遍历连通图的过程中发现所有环路,可采用深度优先策略结合回溯,参考 tarjan 算法,大致是下面代码:

def dfs(node, parent, visited, graph, cycle):
    visited[node] = "grey"
    for neigh in graph[node]:
        if visited[neighbor] == "white":
            dfs(neigh, node, visited, graph, cycle)
        elif visited[neigh] == "grey" and neigh != parent:
            # 发现环路,从当前节点到 neighbor 的路径构成一个环
            # 回溯过程中直接冒泡最大边并标记,代码写不好,算了
            cycle.append(list(reverse_path(path[node]) + [node, neigh, weight]))
    visited[node] = "black"

def find_cycles(graph):
    visited = {node: "white" for node in graph}
    cycles = []
    for node in graph:
        if visited[node] == "white":
            dfs(node, None, visited, graph, cycles)
    return cycles

深度优先遍历结束后,直接把所有标记的边砍掉即可,时间复杂度被边数量,回溯深度影响,控制在 O(EV)。有个细节点,如果一条边同时是两个环的最大边,则需要再砍一刀,否则就需要再遍历一次而不可止:
在这里插入图片描述

以上算法只是一个可行性说明,在更普遍场景,这个算法应由多节点并行完成,各节点相互交互转发 [节点,边,权重] 的 list 信息来判断出环路,由最大边所连接节点自行 block 该边。我说的 STP 大致是这个意思,说的就是这。

仍以老图为例,给出一个交互示例,也用几何表示,给出用肉眼识别环路的方法:
在这里插入图片描述

通过交互消息发现环路,自己阻塞端口,这就是 STP 的绝佳实例。而对于上图右边部分,给一个菌类生长形态的类比:
在这里插入图片描述
浙江温州皮鞋湿,下雨进水不会胖。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值