最小树形图模板朱刘算法分享

最小树形图模板朱刘算法分享

最小树形图(Minimum Spanning Arborescence)是有向图的一种特殊的生成树,它包含了图中所有的点且仅有一个点入度为0(源点)。朱刘算法是一种求解最小树形图的算法,时间复杂度为$O(VE)$。

以下是朱刘算法的完整攻略:

1. 算法原理

朱刘算法基于”缩点”思想和“基环树”的性质,在每一个生成树已经连出来的点(包括源点)中选择一个代表进行缩点,每次将点进行缩点,并记缩点后连出去的边的最小边权作为这个点的代价,缩点后生成的新图上执行贪心算法来找到最小树形图。如果新图中存在环,就对环进行“缩环”,将环上的若干个点缩成一个点,重新生成一个新图,递归地执行缩点/缩环操作,直到得到一棵树为止。

2. 详细步骤

按照如下步骤执行朱刘算法:

  • 构建一个新图 $G'$,其中新图的顶点与 $G$ 的强连通分量一一对应。
  • 对强连通分量内部进行缩点。这个过程需要在线性时间内完成,并确定构建新图 $G'$ 后,对应的新源点。
  • 对 $G'$ 执行普通的 Prim 或 Kruskal 算法。这两个算法都能在线性时间内找到 $G'$ 的最小生成树。
  • 如果生成的最小树不包含新源点,算法结束。
  • 如果生成的最小树包含新源点,则需要查找环。对于任意一条从新源点开始的出边 $(u,w)$,在缩点后的点集合中,找到 $(u,w)$ 所指向的顶点 $v$。如果 $v$ 已经在环中,则不需要再次寻找环。否则,从 $v$ 开始继续深度遍历,得到一个环,并从中选取一条基本边 e,再执行缩环操作
  • 缩环后需要重新建图。对于原图 $G$ 中的每个顶点,找到新图 $G'$ 中所代表的强连通分量,把该顶点标记为这个分量的代表点,并把这个顶点所在的连通分量的所有边都放进一个集合里。
  • 在这个新的图上,重复步骤3,直到找到一棵不包含新源点的最小生成树。

3. 算法实现

这里提供一个实现朱刘算法的Python代码示例:

import sys
from typing import List, Tuple

INF = sys.maxsize


def add_edge(u: int, v: int, w: int, adj: List[List[Tuple[int, int]]]) -> None:
    adj[u].append((v, w))


def update(son: List[int], delta: List[int], dad: List[int], x: int) -> None:
    delta[x] = INF
    for i in range(len(son)):
        y = son[i]
        if dad[y] == x:
            update(son, delta, dad, y)
            delta[x] = min(delta[x], delta[y])

        delta[x] = min(delta[x], delta[y] - INF)


def zhu_liu(n: int, root: int, edges: List[Tuple[int, int, int]]) -> Tuple[int, List[int]]:
    """zhu_liu algorithm

    Args:
        n (int): total number of vertices
        root (int): root of the minimum spanning arborescence
        edges (List[Tuple[int, int, int]]): edges of the graph, (u, v, w)

    Returns:
        Tuple[int, List[int]]: minimum cost and MST
    """
    m = len(edges)
    dad = [root for _ in range(n)]
    best = [INF for _ in range(n)]
    vis = [False for _ in range(n)]

    for _ in range(n):
        for j in range(m):
            u, v, w = edges[j]
            if best[v] > w and u != v:
                best[v] = w
                dad[v] = u

        for j in range(n):
            if j == root:
                continue
            if best[j] == INF:
                return -1, []
            update([j], best, dad, j)
            for k in range(len(edges)):
                u, v, w = edges[k]
                if dad[u] != u and best[v] == w:
                    dad[v] = u
                    break

        if dad[root] == root:
            return sum(best), dad

        cur = root
        next_ = root
        while vis[cur]:
            cur = dad[cur]
        while not vis[cur]:
            vis[cur] = True
            cur = dad[cur]
        for i in range(n):
            if vis[i]:
                best[i] -= best[cur]
                dad[i] = cur
            else:
                best[i] -= best[next_]

        root = next_

    return -1, []

4. 示例说明

以下是两个使用朱刘算法求解最小树形图的示例:

示例 1:

给定图 $G$,如下所示:

       1      6      7
   o ---> o ---> o ---> o
   | 4    /\     |    / |
2  |    /    \   |  /   |8
   v  /      \  v /    v
   o <---- o <--- o <--- o
      5      3      9

执行朱刘算法后,得到生成的最小树形图如下:

        6          7
    o ---> o ---> o
    |      /       |                  
   2|    /    8    |5  
    v  /          v           
    o <-----------o
         3

示例 2:

给定图 $G$,如下所示:

        3    2    5
    o ---> o ---> o
    | _ 2 /      |                  
   1| _\_/        |1  
    v             v           
    o ------------o
          6

执行朱刘算法后,得到生成的最小树形图如下:

        3          5
    o ---> o ---> o                  
    |            / |                  
   1|          /   |1  
    v        /     v           
    o <-----o <----o
          6      2

参考

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:最小树形图模板朱刘算法分享 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • jsp中变量及方法的声明与使用

    一、JSP中变量声明与使用 在JSP中,我们可以使用JSP表达式和JSP脚本来声明和使用变量。其中,JSP表达式使用${ },而JSP脚本则使用<% %>。 JSP表达式 JSP表达式可以用来在页面中输出一个变量的值,或者把表达式的结果赋值给一个变量。使用JSP表达式声明的变量只在当前页面中有效。 示例1: <% String name =…

    Java 2023年6月15日
    00
  • Java中的ArrayIndexOutOfBoundsException是什么?

    ArrayIndexOutOfBoundsException是Java中的一个异常类,用于处理数组下标越界的情况。当数组的下标越界时,抛出该异常。 以下是一个简单的示例: int[] arr = new int[5]; arr[6] = 10; 上述示例中,数组arr的长度为5,但我们试图使用下标6来访问该数组。由于数组的大小为5,因此下标必须在0到4之间。…

    Java 2023年4月27日
    00
  • 浅谈JS如何写出漂亮的条件表达式

    下面是详细讲解“浅谈JS如何写出漂亮的条件表达式”的完整攻略: 1. 使用三元运算符 三元运算符是一种简洁的条件表达式语法,可以用来简化if-else语句的编码。三元运算符包含一个条件判断语句和两个表达式,形式如下: condition ? expression1 : expression2 其中,condition是一个布尔表达式,如果计算结果为true,…

    Java 2023年6月15日
    00
  • java生成自增编号数字的问题

    生成自增编号是Java应用程序开发中经常出现的需求,可以为数据库中的表设置自增主键,也可以为业务中不同种类的数据生成不同的编号。本篇攻略将介绍如何使用Java来实现自增编号。 方案一:使用数据库的自增主键 数据库中可以设置自增主键,通过以下步骤实现: 在数据库中创建自增主键 CREATE TABLE user ( id INT PRIMARY KEY AUT…

    Java 2023年5月20日
    00
  • Java输入/输出流体系详解

    Java输入/输出流体系详解 引言 Java的输入/输出流是Java程序中使用频率很高的部分,从文件IO到网络IO,从字节流到字符流,从节点流到处理流,Java的IO体系都非常的强大和灵活。许多初学者在学习Java IO时经常会对Java IO体系的各个部分感到困惑和无从下手。本篇攻略就是希望能够帮助读者理解Java IO体系的各个方面,掌握Java输入/输…

    Java 2023年5月26日
    00
  • SpringBoot启动原理深入解析

    SpringBoot启动原理深入解析 什么是SpringBoot? SpringBoot是基于Spring框架的一套快速开发框架,采用约定优于配置的思想,目的在于简化Spring应用的创建和开发过程。 SpringBoot启动过程 SpringBoot启动过程涉及到的类和接口有很多,下面对SpringBoot启动过程的核心部分做一个简单的介绍。 Spring…

    Java 2023年5月15日
    00
  • tomcat自定义Web部署文件中docBase和workDir的区别介绍

    当我们将Web应用部署到Tomcat服务器上时,可以在Tomcat配置文件中自定义Web应用。在Tomcat配置文件中,有两个重要的属性:docBase和workDir。这两个属性在Tomcat上非常重要,因为它们决定了Web应用的部署位置和缓存位置。 docBase属性 docBase属性指定了Web应用的根目录。Tomcat会在docBase路径下查找W…

    Java 2023年6月15日
    00
  • 详解如何通过tomcat的ManagerServlet远程部署项目

    关于如何通过Tomcat的ManagerServlet远程部署项目,可以按照以下步骤进行: 1. 开启Tomcat的ManagerServlet 在Tomcat的conf/tomcat-users.xml配置文件中添加ManagerServlet的访问权限,示例代码如下: <tomcat-users> <!– 添加ManagerServl…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部