【做练习】SPF(图论求割点,Tarjan割点算法)

题目

总时间限制: 1000ms 内存限制: 65536kB

描述

Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a failure of a single node, 3, in the network on the left would prevent some of the still available nodes from communicating with each other. Nodes 1 and 2 could still communicate with each other as could nodes 4 and 5, but communication between any other pairs of nodes would no longer be possible.

Node 3 is therefore a Single Point of Failure (SPF) for this network. Strictly, an SPF will be defined as any node that, if unavailable, would prevent at least one pair of available nodes from being able to communicate on what was previously a fully connected network. Note that the network on the right has no such node; there is no SPF in the network. At least two machines must fail before there are any pairs of available nodes which cannot communicate.

在这里插入图片描述

输入

The input will contain the description of several networks. A network description will consist of pairs of integers, one pair per line, that identify connected nodes. Ordering of the pairs is irrelevant; 1 2 and 2 1 specify the same connection. All node numbers will range from 1 to 1000. A line containing a single zero ends the list of connected nodes. An empty network description flags the end of the input. Blank lines in the input file should be ignored.

输出

For each network in the input, you will output its number in the file, followed by a list of any SPF nodes that exist.

The first network in the file should be identified as “Network #1”, the second as “Network #2”, etc. For each SPF node, output a line, formatted as shown in the examples below, that identifies the node and the number of fully connected subnets that remain when that node fails. If the network has no SPF nodes, simply output the text “No SPF nodes” instead of a list of SPF nodes.

样例输入

1 2
5 4
3 1
3 2
3 4
3 5
0

1 2
2 3
3 4
4 5
5 1
0

1 2
2 3
3 4
4 6
6 3
2 5
5 1
0

0

样例输出

Network #1
SPF node 3 leaves 2 subnets

Network #2
No SPF nodes

Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets

翻译一下

在计算机网络上有若干节点,输入给你若干点对点的连接。

定义“SPF”为这样的节点:如果删除它,它所在的网络将被划分为若干个子网,每个子网内部连通,但子网之间不连通。

对于每个case,让你输出其中所有的SPF,以及这些SPF把它所在网络分割为了几个子网。

分析

很直白了,所谓SPF就是求割点,并求出割点所分割的连通分量数(我们称为割数)。我们使用Tarjan算法。

Tarjan割点算法

Tarjan割点算法使用深度优先搜索方式建立一棵搜索树。需要为每个节点维护变量dfn和low。dfn记录它被搜索到的次序,low则记录包含该节点的任何环路中的最小dfn。初始时,low=dfn。

我们在递归搜索的同时,计算出每个节点的low。

  • 根据图的性质:对于连通图的任何生成树,如果一个节点u到另一节点v有【非父子边】,则必定有环路经过u和v。所以当我们找到一个节点u,它存在非父子边达到已经搜索过的节点v时,说明有环,我们更新low[u]为min(low[u], dfn[v])。
  • 而当搜索回溯时,我们更新low[u]为min(low[u], low[v])——因为如果low[v]<low[u](我们知道dfn[v] > dfn[u]),必然是因为v之后找到环了,且这个环肯定会经过先于u被搜索到的节点。

怎么求割数呢?

  • 如果一个节点v是搜索树的根,则它的割数为搜索树上,根的子树的个数。
  • 如果一个节点v不是根,那么它的割数为:1 + (v的子节点中,其low不超过v的dfn的子节点个数),也就是 1 + ∣ ∣ { u ∣ u 是 v 的 子 节 点 , 且 过 v 的 环 都 在 u 为 根 的 子 树 中 } ∣ ∣ 1 + ||\{u| u是v的子节点,且过v的环都在u为根的子树中\}||
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tarjan算法和Kosaraju算法都是解有向图强连通分量的算法,它们的时间复杂度都为O(N+M),其中N为图中节点数,M为图中边数。 Tarjan算法的基本思想是通过DFS遍历图中的节点,并在遍历的过程中维护一个栈,用于存储已经遍历过的节点。在遍历的过程中,对于每个节点,记录它被遍历到的时间戳和能够到达的最小时间戳,当一个节点的最小时间戳等于它自身的时间戳时,说明这个节点及其之前遍历到的节点构成了一个强连通分量,将这些节点从栈中弹出即可。 Kosaraju算法的基本思想是先对原图进行一次DFS,得到一个反向图,然后再对反向图进行DFS。在第二次DFS的过程中,每次从未被访问过的节点开始遍历,遍历到的所有节点构成一个强连通分量。 两种算法的具体实现可以参考以下代码: ```python # Tarjan算法 def tarjan(u): dfn[u] = low[u] = timestamp timestamp += 1 stk.append(u) for v in graph[u]: if not dfn[v]: tarjan(v) low[u] = min(low[u], low[v]) elif v in stk: low[u] = min(low[u], dfn[v]) if dfn[u] == low[u]: scc = [] while True: v = stk.pop() scc.append(v) if v == u: break scc_list.append(scc) # Kosaraju算法 def dfs1(u): vis[u] = True for v in graph[u]: if not vis[v]: dfs1(v) stk.append(u) def dfs2(u): vis[u] = True scc.append(u) for v in reverse_graph[u]: if not vis[v]: dfs2(v) # 构建图和反向图 graph = [[] for _ in range(n)] reverse_graph = [[] for _ in range(n)] for u, v in edges: graph[u].append(v) reverse_graph[v].append(u) # Tarjan算法解强连通分量 dfn = [0] * n low = [0] * n timestamp = 1 stk = [] scc_list = [] for i in range(n): if not dfn[i]: tarjan(i) # Kosaraju算法解强连通分量 vis = [False] * n stk = [] scc_list = [] for i in range(n): if not vis[i]: dfs1(i) vis = [False] * n while stk: u = stk.pop() if not vis[u]: scc = [] dfs2(u) scc_list.append(scc) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值