9.5.1 拓扑排序及LeetCode题目 —— Course Schedule II & Minimum Height Trees

首先解释AOV网的概念:

用一个有向无环图DAG表示一项工程或项目,我们用顶点表示活动,用弧\边表示活动之间的优先关系。这样的图称为顶点表示活动的网即AOV网(Active on Vertex Network)。

再看一下拓扑排序topologicalSort

对于任何有向图而言,其拓扑排序为其所有结点的一个线性排序(对于同一个有向图而言可能存在多个这样的结点排序)。该排序满足这样的条件——对于图中的任意两个结点uv,若存在一条有向边从u指向v,则在拓扑排序中u一定出现在v前面。

拓扑排序主要用来解决有向图中的依赖解析(dependency resolution)问题。

拓扑排序算法:

从AOV网中选择一个入度为0的顶点然后删除此顶点,并删除以此顶点为起点的边。重复此步骤,直到输出全部顶点或AOV网中不存在入度为0的顶点为止。

我们可以用广度优先遍历算法来完成拓扑排序。

  1. 新建一个数组,根据已知的邻接表或边,保存每一个结点的入度。
  2. 选取入度为0的结点加入队列。
  3. 从队列中取出一个点,对于遍历过的每个结点,查找其出度表,出度表中的节点因为该点的删除而少了一条边,更新这些点的入度减1,如果入度变为0,也加入到队列中。
  4. 重复步骤3,直到遍历完所有的结点。
  5. 如果无法遍历完所有的结点,则意味着当前的图不是有向无环图。不存在拓扑排序。

拓扑排序的原理和代码都很简单,下面我们看两道LeetCode的题目学习一个。

210. Course Schedule II

There are a total of n courses you have to take labelled from 0 to n - 1.

Some courses may have prerequisites, for example, if prerequisites[i] = [ai, bi] this means you must take the course bi before the course ai.

Given the total number of courses numCourses and a list of the prerequisite pairs, return the ordering of courses you should take to finish all courses.

If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array.

题解:

就是一道给活动(课程)排序的题目,活动之间有依赖关系。结合代码理解上面的算法思路,首先得出图的出度表(邻接表)和入度值表,然后一个个删除入度为0 的点,order里就是拓扑排序的一种结果。

时间复杂度:初始阶段,要检查所有顶点一次,排序时每个点入栈出栈一次,可以认为时间复杂度是O(n)

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        graph = [[] for i in range(numCourses)]
        num_in = [0 for i in range(numCourses)]
        for edge in prerequisites:
            a, b = edge[0], edge[1]
            graph[b].append(a)
            num_in[a] = num_in[a] + 1
        order = []
        stack = []
        for i in range(numCourses):
            if num_in[i] == 0:
                stack.append(i)
                order.append(i)
        while stack:
            course = stack.pop()
            for out in graph[course]:
                num_in[out] = num_in[out] - 1
                if num_in[out] == 0:
                    stack.append(out)
                    order.append(out)
        if len(order) == numCourses:
            return order
        return []

310. Minimum Height Trees

A tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.

Given a tree of n nodes labelled from 0 to n - 1, and an array of n - 1 edges where edges[i] = [ai, bi] indicates that there is an undirected edge between the two nodes ai and bi in the tree, you can choose any node of the tree as the root. When you select a node x as the root, the result tree has height h. Among all possible rooted trees, those with minimum height (i.e. min(h))  are called minimum height trees (MHTs).

Return a list of all MHTs' root labels. You can return the answer in any order.

The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

题解:

这道题蛮有意思,我这里学习了题解里的思路,用拓扑排序的思想解决。由于是无向图,所以从度=1的点开始入栈,逐步删除,直至剩下1、2个点。

解释一下剩下的1-2个点的情况,我们按度=1的条件删除点,最后只能出现两种情况,可以看题目给的示例,例1剩下一个点且度=0,例2,剩下两个点且度=1。

所以按照这个思路剩下<=2个点时即为结果。这里我们用类似广度优先遍历的方法,保证最后剩在stack里的就是最终结果。

 

class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        if n == 1:
            return [0]
        elif n == 2:
            return [0, 1]
        from collections import defaultdict
        graph = defaultdict(list)
        num_in = [0 for i in range(n)]
        for edge in edges:
            graph[edge[0]].append(edge[1])
            graph[edge[1]].append(edge[0])
            num_in[edge[0]] = num_in[edge[0]] + 1
            num_in[edge[1]] = num_in[edge[1]] + 1
        stack = []
        cnt = n
        # 将第一批度=1的入栈
        for i in range(n):
            if num_in[i] == 1:
                stack.append(i)
        while stack:
            tmp = []
            while stack:
                node = stack.pop()
                cnt -= 1
                # 删除这些点及相关边,将下一批度=1的入栈
                for out in graph[node]:
                    num_in[out] = num_in[out] - 1
                    if num_in[out] == 1:
                        tmp.append(out)
            stack = tmp
            if cnt == 2 or cnt == 1:
                return stack

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: pads9.5.1(0630)是指某个软件或应用的版本号。根据这个版本号,可以推测出以下几点信息。 首先,pads9.5.1(0630)中的"pads"可能是该软件或应用的名称。它可能是一个设计软件、绘图工具或其他与电子设计相关的应用。由于没有提供更多的信息,我们不能确定其具体用途。 接着,"9.5.1"是版本号中的一部分,它表示软件或应用当前的主版本号。版本号通常用来标识软件或应用在不同发布或更新时的变化。具体而言,"9.5.1"表示该软件或应用已经更新到了第9主版本,第5子版本和第1修订版本。 最后,"(0630)"可能是与该版本号相关的日期或时间戳。它可能表示软件或应用的发布日期或最后更新的日期。在这种情况下,"(0630)"可能代表该版本是在6月30日发布或更新的。 总之,根据提供的信息,pads9.5.1(0630)是某个软件或应用的版本号,代表了特定软件或应用的更新或发布的日期。如果需要更多的信息,需要进一步了解该软件或应用的背景和用途。 ### 回答2: Pads 9.5.1(0630) 是一个电子设计自动化 (EDA) 软件,主要用于电路设计和印刷电路板 (PCB) 布局。它提供了各种功能,用于创建和编辑电路设计、布线分析、信号完整性分析和板级封装设计。 Pads 9.5.1(0630) 是该软件的一个版本号。版本号中的第一个数字 "9" 表示主要版本号,表示已经进行了大规模的更新和改进。"5" 表示次要版本号,表示在主要版本的基础上进行了一些小的功能修改和改进。"1" 是修订版本号,表示进行了矫正和补丁更新。最后的 "(0630)" 是发布日期或构建编号,用于区分不同的版本和修订。 使用 Pads 9.5.1(0630),用户可以创建电路图和进行布线,通过添加器件、连接导线和电源线等来构建电路。用户可以选择不同的器件库,根据需要选择适合的元件,并灵活调整其参数和属性。在设计完成后,用户可以进行信号完整性分析,以确保电路的信号传输和稳定性。还可以进行布局分析,以确保电路板上的元件安排得当,满足电磁兼容 (EMC) 要求。 Pads 9.5.1(0630) 还提供了与其他 CAD 软件的集成能力,例如与机械设计软件的接口,以支持整体设计和协同工作。此外,它还支持标准的 PCB 文件格式,如 Gerber,以便与其他生产和制造环节进行交互。 总之,Pads 9.5.1(0630) 是一个功能强大的电子设计自动化软件,提供了绘制电路图、布线分析和信号完整性分析等功能,可用于辅助电路设计师和 PCB 工程师进行电子元件和电路板的设计和优化。 ### 回答3: pads9.5.1(0630) 是一个软件版本号,它代表了一款电子设计自动化软件 PADS 的特定版本号和发行日期。 PADS 是 Mentor Graphics 公司开发的一款电子设计自动化 (EDA) 软件,用于电子电路的设计、仿真和布局。这款软件的版本号是 9.5.1,表示该版本是 9.5 版本的第一个修正版本。 而后面的 (0630) 则表示该版本的发行日期,即在 2021 年 6 月 30 日发布。这个日期可能代表了软件的最后更新和修复的时间节点,意味着该版本在这一天之后可能已经停止更新,并可能被新的版本所取代。 使用软件时,我们通常可以通过版本号来确认我们所使用的软件的特定版本。版本号可以帮助我们确定软件的功能和特性,并判断是否有新的版本可用。在更新软件时,我们可以查看最新的版本号,并了解到新版本可能带来的改进和修复。这样可以帮助我们更好地选择和使用适合自己需求的软件版本,以获得更好的使用体验和性能。 综上所述,PADS9.5.1(0630) 是 Mentor Graphics 公司开发的一款电子设计自动化软件的特定版本号和发行日期。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值