📜  门| GATE CS 2018 |简体中文第39章(1)

📅  最后修改于: 2023-12-03 15:28:37.973000             🧑  作者: Mango

门| GATE CS 2018 |简体中文第39章

本文将介绍GATE CS 2018考试中的第39章,该章节主要涵盖了:

  • 有向图的强连通分量(SCC)
  • Prim算法
  • Kruskal算法
有向图的强连通分量(SCC)
定义
  • 在一个有向图中,如果从一个顶点可以到达另一顶点,且从另一顶点也可以到达该顶点,则称它们形成一个强连通分量。
  • 一个有向图可以被分成若干个强连通分量,每个强连通分量都是没有一个图中的点能到达该强连通分量中的其他点。
  • 求解强连通分量,通常使用Tarjan算法或Kosaraju算法。
Tarjan算法

Tarjan算法是求解有向图强连通分量的常用算法之一。它的时间复杂度为O(m+n),其中m为有向图中的边数,n为顶点数。

算法步骤:

  1. 维护一个时间戳变量。
  2. 对于每个顶点v,从v开始进行深度优先遍历,记录遍历到的顶点编号和时间戳。
  3. 如果某个顶点u可以调用子树t中的任何顶点返回的时间早于u本身的时间,那么u和t中的点构成一个强连通分量。

示例代码:

def TarjanSCC(graph):
    n = len(graph)
    ID = [0] * n
    low = [0] * n
    onstack = [False] * n
    stack = []
    time = 0
    SCCs = []

    def dfs(u):
        nonlocal time
        ID[u] = low[u] = time
        time += 1
        stack.append(u)
        onstack[u] = True

        for v in graph[u]:
            if ID[v] == 0:
                dfs(v)
                low[u] = min(low[u], low[v])
            elif onstack[v]:
                low[u] = min(low[u], ID[v])

        if ID[u] == low[u]:
            scc = []
            while True:
                v = stack.pop()
                onstack[v] = False
                scc.append(v)
                if v == u:
                    break
            SCCs.append(scc)

    for u in range(n):
        if ID[u] == 0:
            dfs(u)

    return SCCs
最小生成树算法

最小生成树算法是求解图的最优子结构的一个经典问题。它的具体含义为,给定一个无向图,求其生成树中总边权最小的那棵树。

Prim算法

Prim算法是一种贪心算法,其思路为从一个顶点开始,每次添加到生成树集合中的边权最小的那条边,直到所有顶点都被添加到生成树中为止。

算法步骤:

  1. 从一个起点开始,将其加入生成树集合,然后将与它相邻的所有顶点加入到优先队列(堆)中。
  2. 从队列中选出边权最小的顶点,将其加入到生成树中,并将其相邻的顶点加入到队列中。
  3. 重复以上步骤,直到所有顶点都被加入到生成树中。

示例代码:

import heapq

def prim(graph, s=0):
    n = len(graph)
    marked = [False] * n
    mst = []
    pq = []

    def visit(u):
        marked[u] = True
        for v, w in graph[u]:
            if not marked[v]:
                heapq.heappush(pq, (w, u, v))

    visit(s)

    while pq:
        w, u, v = heapq.heappop(pq)
        if not marked[v]:
            marked[v] = True
            mst.append((u, v, w))
            visit(v)

    return mst
Kruskal算法

Kruskal算法也是一种贪心算法,其思路为在图中找到边权最小的边,将其加入生成树中,并判断是否形成了环,如果没有形成环,则将该边加入当前生成树中。

算法步骤:

  1. 将所有边按照边权从小到大排序。
  2. 从边权最小的边开始,依次将其加入生成树中。
  3. 如果加入该边会形成环,则舍弃该边,否则将该边加入当前生成树中。

示例代码:

def kruskal(graph):
    n = len(graph)
    mst = []
    uf = UnionFind(n)
    edges = sorted((w, u, v) for u, e in graph.items() for v, w in e)

    for w, u, v in edges:
        if uf.find(u) != uf.find(v):
            uf.union(u, v)
            mst.append((u, v, w))

    return mst

以上就是GATE CS 2018考试中第39章的内容介绍。涵盖了有向图的强连通分量和两种最小生成树算法(Prim算法和Kruskal算法)。对于算法学习和应用都有很大的参考价值。