即使在您进行第二次编辑后,我仍然不确定您的实际目标是什么。您选择的术语会阻碍这一点。大多数人的意思是,SCC 是彼此可到达的最大顶点集,可能发生的路径根本无关紧要。
有人知道在 SCC 中找到 SCC 的方法吗?
按照通常的定义,在 SCC 中没有 SCC 这样的东西,因为 SCC 是最大的。
您正在寻找其他东西:您从一个连通图开始,并希望找到您没有很好地表征的特定边集。我强烈怀疑,如果您确实以清晰的方式描述了您想要的内容,那么算法将会失败。
我的第一个猜测是,对于给定的连通图,您需要连接每对的所有路径的所有可能组合的边集。如果是这种情况,直接的方法是:对于每一对,找到所有路径,然后找到所有组合并消除重复项。但是,这会生成比您在示例中列出的更多的集合,因为使用所有边当然是可能的。
相反,您似乎希望所有 最小 边集仍然让原始顶点保持为 SCC。在这种情况下,原始边集的 power set 的每个元素都代表一个可能的候选者,并且您希望所有候选者的图仍然连接,但没有适当的子集仍然连接。
这给出了一个简单的算法来遍历这个集合格并检查这个条件。检查图是否连接是直截了当的,删除或添加边也是如此。但是,类似的图表具有大部分相同的结构,因此您需要重用以前问题中的内容。
一些可能有帮助的参考资料:
特别是在将图的全局信息与关于边和顶点的局部信息联系起来方面。
你的起始图 G 有一组顶点 V 和边 E,并且是强连通的。
目标是输出所有“最小”的边集 E',以便从 E 中删除任何边将图形分成多个 SCC。我们可以通过搜索所有可能的边缘集来做到这一点。
直截了当:
for E' in powerset(E):
if (V, E') strongly connected:
for e in E':
if (V, E' - e) strongly connected:
try next E' # Not minimal
add G' = (V, E') to list of minimal subsets.
然而这是非常浪费的:显然不连通的图是
测试,每个图的连通性都测试了很多次。
我们可以通过搜索可能的边缘集来消除第一个
以更好的顺序,将这些边集排列成格子。每个
边缘集具有由该边缘集减去一个边缘给出的“直接子代”。
一旦我们遇到一个不是 SCC 的图,我们就不需要检查任何
它的子集,因为它们也不能是 SCC。最简单的表达方式
这是作为图形搜索。虽然深度优先搜索通常是
路要走,因为它使用较少的内存,我将首先选择一个广度
搜索,因为稍后我们将使用遍历的顺序。 (一个深度
first search 将队列更改为堆栈)。
push starting node on queue
while queue not empty:
pop node from queue
for c in suitable children, not on queue:
push c on queue
deal with node
“不在队列中”部分很关键,否则每个节点都可以访问
很多次。这将我们的算法变成:
push E on queue
while queue not empty:
pop E' from queue
if (V, E') strongly connected:
minimal = true
for e in E':
if (V, E' - e) strongly connected:
push E' - e on queue if not on queue
minimal = false
if minimal:
add G' = (V, E') to list of minimal subsets.
现在它会跳过所有不可能强连接的边缘集,
因为超集也不是。缺点是可以
可能会占用大量空间。然而,它仍然反复检查
连接性。但是,我们可以缓存这些信息。
check_or_add_cached_connected(E)
push E on queue
while queue not empty:
pop E' from queue
connected = cached (E')
if connected:
minimal = true
for e in E':
child_connected = check_or_add_cache(E' - e)
if child_connected:
push E' - e on queue if not on queue
minimal = false
if minimal:
add G' = (V, E') to list of minimal subsets.
remove E' from cache
现在我们已经开始缓存,我们可以缓存更多内容。如果
删除一条边会破坏图,它也会破坏任何子图。
这意味着我们可以跟踪图中的“所需边”,并且
将它们传播到任何子图。我们可以检查这些必需的
边缘以避免检查子图。
check_or_add_cached_connected(E)
push E on queue
while queue not empty:
pop E' from queue
(connected, required_edges) = cached (E')
if connected:
minimal = true
for e in E' and not in required_edges:
child_connected = check_or_add_cached_connected(E' - e)
if child_connected:
push E' - e on queue if not on queue
minimal = false
else:
add e to required_edges
if minimal:
add G' = (V, E') to list of minimal subsets.
else:
for e in E' and not in required_edges:
merge_cache(E' - e, required_edges)
remove E' from cache
缓存和队列的结构确实需要做一些工作来确保可以有效地完成所使用的操作,但这相当简单。