算法导论 第22章 基本的图算法 22.1 图的表示 习题解答

22.1-1 给定有向图的邻接链表,需要多长时间才能计算出每个结点的出度(发出的边的条数)?多长时间才能计算出每个结点的入度(进入的边的条数)?

计算有向图中每个节点的出度和入度的时间复杂度取决于图的表示方式和规模。

1. 出度计算:

对于邻接链表表示的有向图,计算每个节点的出度需要遍历图中的每个节点,然后对于每个节点,遍历其邻接链表,统计邻接节点的数量即为该节点的出度。因此,出度的计算时间复杂度为O(V + E),其中V是节点的数量,E是边的数量。2. 入度计算:

对于有向图的入度,需要对图中的每个节点进行遍历,然后再对每个节点的邻接链表进行遍历,统计指向该节点的边的数量即为该节点的入度。入度的计算时间复杂度也为O(V + E)。

总体而言,计算出度和入度的时间复杂度都是O(V + E),其中V是节点数,E是边数。因为你需要遍历每个节点,并检查它们的邻接链表中的边的数量。

22.1-2 给定一棵有7个结点的完全二叉树的邻接链表,请给出等价的邻接矩阵表示。这里假设给定的编号为从1~7。

   1  2  3  4  5  6  7

1  0  1  1  0  0  0  0

2  1  0  0  1  1  0  0

3  1  0  0  0  0  1  1

4  0  1  0  0  0  0  0

5  0  1  0  0  0  0  0

6  0  0  1  0  0  0  0

22.1-3 有向图G = (V, E)的转置是图GT = (V, ET),这里ET = {(v, u) ∈ V * V:(u, v) ∈E}。因此,图GT就是将有向图G中所有边的方向反过来而形成的图。对于邻接链表和邻接矩阵两种表示,请给出从图G计算出GT的有效算法,并分析算法的运行时间。

1. 针对邻接链表的转置算法:

对于邻接链表表示的有向图G,计算其转置GT的算法可以通过以下步骤实现:

  1. 创建一个新的空图GT的邻接链表。
  2. 对于图G中的每个节点v,遍历其邻接链表中的每个邻接节点u。
  3. 将边(u, v)添加到图GT的邻接链表中。

这个算法的时间复杂度为O(V + E),其中V是节点数,E是边数。因为需要遍历每个节点和每条边一次。

2. 针对邻接矩阵的转置算法:

对于邻接矩阵表示的有向图G,计算其转置GT的算法可以通过以下步骤实现:

  1. 创建一个新的空图GT的邻接矩阵。
  2. 对于图G中的每条边(u, v),将其对应位置的邻接矩阵中的值设置为1。
  3. 通过遍历邻接矩阵,将每个位置(i, j)的值与位置(j, i)的值交换。

这个算法的时间复杂度为O(V^2),其中V是节点数。因为需要遍历每个位置两次:一次设置原始边的值,一次进行转置。

其中,邻接链表表示的算法对于稀疏图可能更有效,而邻接矩阵表示的算法对于稠密图可能更有效。

22.1-4 给定多图G = (V, E)的邻接链表(多图是允许重复边和自循环边的图),请给出一个时间为O(V+E)的算法,用来计算该图的“等价”无向图G’ = (V, E’)的邻接链表表示。这里E’是将E中的冗余边和自循环边删除后余下的边。删除冗余边指的是将两个结点之间的多条边替换为一条边。

对于每个顶点 v 属于 V:

    创建一个用于跟踪顶点 v 的已访问顶点的空集合

    对于 v 的邻接链表中的每条边 (v, u):

        如果 u 不在顶点 v 的已访问顶点集合中:

            将边 (u, v) 添加到图 G' 的邻接链表中

            将 u 添加到顶点 v 的已访问顶点集合中

这个算法遍历每个顶点,然后遍历每个顶点的邻接链表,将每条边 (u, v) 添加到 G' 的邻接链表中,同时使用集合来确保不重复添加边。算法的时间复杂度为 O(V + E),其中 V 是顶点数,E 是边数。

22.1-5 有向图G = (V, E)的平方图是图G^G = (V, E^2),这里,边(u, v)∈E^2当且仅当图G包含一条最多由两条边构成的从u到v的路径。请给出一个有效算法来计算图G的平方图G^2。这里图G既可以以邻接链表表示,也可以以邻接矩阵表示。请分析算法的运行时间。

1.针对邻接矩阵的算法:

计算矩阵 A = G * G(矩阵乘法)。

创建一个新的空图G^2的邻接矩阵。

对于矩阵A的每个元素A[i][j],如果A[i][j] > 0,则在G^2的邻接矩阵中将对应位置的值设置为1。

算法的时间复杂度为O(V^3),其中V是节点数。这是因为计算矩阵乘法的时间复杂度是O(V^3)。

2.针对邻接链表的算法:


def square_graph(adjacency_list):

    graph_squared = {vertex: set() for vertex in adjacency_list}



    for v, neighbors in adjacency_list.items():

        for u in neighbors:

            for w in adjacency_list[u]:

                graph_squared[v].add(w)



return graph_squared
  1. `graph_squared = {vertex: set() for vertex in adjacency_list}`: 创建一个空的字典 `graph_squared`,该字典的键是原图G的节点,值是相应节点在平方图G^2中的邻接节点集合。这里使用集合是为了确保在平方图中不添加重复的边。
  2. `for v, neighbors in adjacency_list.items():`: 对于图G的每个节点v以及其邻接节点的集合neighbors。
  3. `for u in neighbors:`: 对于v的每个邻接节点u。
  4. `for w in adjacency_list[u]:`: 对于u的每个邻接节点w。
  5. `graph_squared[v].add(w)`: 将w添加到平方图G^2中节点v对应的邻接节点集合中。这一步是在G^2中添加由G中的边构成的路径。

最终,`graph_squared` 将包含所有由G中的边构成的路径,形成了平方图G^2的邻接链表表示。

这个算法的时间复杂度是O(|E| * |V| + |V|),其中|E|是边数,|V|是节点数。这是因为对于每个节点v,对其邻接链表中的每个邻接节点u,以及u的邻接链表中的每个节点w,都会执行一次操作,总的时间复杂度是边数和节点数的乘积。

22.1-6 多数以邻接矩阵作为输入的图算法的运行时间为Ω(V^2),但也有例外。给定图G的邻接矩阵表示,请给出一个O(V)时间的算法来判断有向图G是否存在一个通用汇点。通用汇点指的是入度为|V|-1但出度为0的结点。

1. 找到潜在的候选汇点: 遍历图的每个节点,检查其出度和入度。如果出度为0,它可能是通用汇点的候选。

2. 验证候选汇点: 对于每个候选汇点,检查它是否满足条件。遍历图的每个节点,检查从候选汇点到其他节点是否存在边,同时确保所有其他节点都有指向候选汇点的边。这可以在O(V)时间内完成。


def has_universal_sink(adj_matrix):

    num_vertices = len(adj_matrix)



    candidate_sink = 0  # 候选通用汇点

    for vertex in range(1, num_vertices):

        # 如果当前候选汇点的出度不为0,更新候选汇点

        if adj_matrix[candidate_sink][vertex] == 1:

            candidate_sink = vertex



    # 验证候选汇点是否满足条件

    for vertex in range(num_vertices):

        # 跳过候选汇点本身

        if vertex == candidate_sink:

            continue

        # 如果候选汇点有其他节点没有指向候选汇点的入边,则它不是通用汇点

        if adj_matrix[vertex][candidate_sink] != 1:

            return False



    return True



# 示例

adjacency_matrix = [

    [0,1,0],

    [0,0,0],

    [0,1,0]

]



result = has_universal_sink(adjacency_matrix)

print(result)

  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值