图论 SCC(CCF高速公路)

简介

首先需要复习一下图论的一系列知识,理解有向图的强连通分量的定义,求解有向图的强连通分量算法有很多,例如Kosaraju,Gabow和Tarjan算法,其中Gabow和Tarjan算法时间复杂度要优于Kosaraju。在这里我们使用Tarjan求解SCC。
在此之前你可以对SCC有个直观的认识,放图:
强连通分量求解过程
然后看一篇浅显的说明性的文字,了解这个算法的思想:
http://www.voidcn.com/blog/wr132/article/p-4891712.html
然后我们需要贴一篇经典的文章讲解,传送门如下:
https://www.byvoid.com/blog/scc-tarjan/

理解:

核心思想:一个强连通分量中任意两个节点一定是互相可达的,那么这个强连通分量的从i到j的路径构成一个环(when i=j),因此我们的核心思想就是寻找环。
1. DFN[i]数组存储第i个节点的访问时间time,LOW[i]数组存储当前第i个节点能够直接或者间接访问到的最早的节点的时序time
2. 本算法基于DFS,当遍历到第i个节点的时候,递归结束的条件就是考虑第i个节点的DFN值和LOW是否相等,通俗点说就是这个点能找到的最小时间的点是自身,即从i出发可以回到i,那么i后面遍历到的点包括i在内构成了一个有向图的强连通分量。
3. 其次我们考虑递归遍历的时候,第i个节点的下一个节点i+1如果遍历完毕,我们考虑i+1的LOW值,取i和i+1的LOW值中小的;如果i+1在栈中,说明之前遍历过,如果DFN值小,说明之前遍历过,从当前i到i+1很可能构成环,取之。
下面用一道CCF的题目应用一下SCC算法。


问题描述
  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
  现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
  国王想知道,在大臣们给他的计划中,有多少个便利城市对。
输入格式
  输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。
  接下来m行,每行两个整数a, b,表示城市a有一条单向的高速公路连向城市b。
输出格式
  输出一行,包含一个整数,表示便利城市对的数量。
样例输入
5 5
1 2
2 3
3 4
4 2
3 5
样例输出
3

题解

  1. 本题思路在于求出SCC,每个SCC内部的任意两个节点都是相互可达的,我们使用 C
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SCC (Strongly Connected Components) 算法是一种用于寻找有向图中强连通分量算法。下面是一个使用 Python 实现 SCC 算法的例子: ```python from collections import defaultdict class Graph: def __init__(self, vertices): self.graph = defaultdict(list) # 使用 defaultdict 创建邻接表 self.V = vertices def addEdge(self, u, v): self.graph[u].append(v) # 将边添加到邻接表中 # 深度优先搜索函数 def DFS(self, v, visited, stack): visited[v] = True for i in self.graph[v]: if visited[i] == False: self.DFS(i, visited, stack) stack.append(v) # 反转图的边 def reverseGraph(self): g = Graph(self.V) for i in self.graph: for j in self.graph[i]: g.addEdge(j, i) return g # 寻找强连通分量 def findSCCs(self): stack = [] visited = [False] * (self.V) # 第一次 DFS,将顶点按照结束时间压入栈中 for i in range(self.V): if visited[i] == False: self.DFS(i, visited, stack) # 反转图的边 gr = self.reverseGraph() visited = [False] * (self.V) scc_list = [] # 从栈中取出顶点,进行第二次 DFS while stack: v = stack.pop() if visited[v] == False: scc = [] gr.DFS(v, visited, scc) scc_list.append(scc) return scc_list # 测试代码 g = Graph(5) g.addEdge(1, 0) g.addEdge(0, 2) g.addEdge(2, 1) g.addEdge(0, 3) g.addEdge(3, 4) print("强连通分量为:") scc_list = g.findSCCs() for scc in scc_list: print(scc) ``` 以上代码实现了 SCC 算法,通过构建图并使用深度优先搜索来查找强连通分量。测试代码中的图是一个简单的有向图,输出结果会显示图中的强连通分量。运行代码后,输出应为: ``` 强连通分量为: [3, 4] [0, 2, 1] ``` 这表示图中有两个强连通分量,一个包含节点 3 和 4,另一个包含节点 0、2 和 1。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值