gpt4 book ai didi

algorithm - 如何将强连通分量减少到一个顶点?

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:10:00 25 4
gpt4 key购买 nike

来自 https://algs4.cs.princeton.edu/42digraph/

  1. Reachable vertex in a digraph. Design a linear-time algorithm to determine whether a digraph has a vertex that is reachable from every other vertex.

Kosaraju-Sharir algorithm给了我们强连接的组件。可以看到其 Java 代码 here .将每个 SCC 减少为单个顶点,出度为零的顶点可以相互可达。

问题是,每个人似乎都在谈论减少 SCC 而没有提供细节。这样做的有效算法是什么?

最佳答案

以下是针对我自己的问题的 Java 解决方案。对于图形表示,它使用来自 https://github.com/kevin-wayne/algs4edu.princeton.cs:algs4:1.0.3 .似乎有用于图形收缩的通用算法,如 this paper 中所述。 ;但是,就我的目的而言,以下内容就足够了。

/**
* 43. <b>Reachable vertex.</b>
* <p>
* DAG: Design a linear-time algorithm to determine whether a DAG has a vertex that is reachable from every other
* vertex, and if so, find one.
* Digraph: Design a linear-time algorithm to determine whether a digraph has a vertex that is reachable from every
* other vertex, and if so, find one.
* <p>
* Answer:
* DAG: Consider an edge (u, v) ∈ E. Since the graph is acyclic, u is not reachable from v.
* Thus u cannot be the solution to the problem. From this it follows that only a vertex of
* outdegree zero can be a solution. Furthermore, there has to be exactly one vertex with outdegree zero,
* or the problem has no solution. This is because if there were multiple vertices with outdegree zero,
* they wouldn't be reachable from each other.
* <p>
* Digraph: Reduce the graph to it's Kernel DAG, then find a vertex of outdegree zero.
*/
public class Scc {
private final Digraph g;
private final Stack<Integer> s = new Stack<>();
private final boolean marked[];
private final Digraph r;
private final int[] scc;
private final Digraph kernelDag;

public Scc(Digraph g) {
this.g = g;
this.r = g.reverse();
marked = new boolean[g.V()];
scc = new int[g.V()];
Arrays.fill(scc, -1);

for (int v = 0; v < r.V(); v++) {
if (!marked[v]) visit(v);
}

int i = 0;
while (!s.isEmpty()) {
int v = s.pop();

if (scc[v] == -1) visit(v, i++);
}
Set<Integer> vPrime = new HashSet<>();
Set<Map.Entry<Integer, Integer>> ePrime = new HashSet<>();

for (int v = 0; v < scc.length; v++) {
vPrime.add(scc[v]);
for (int w : g.adj(v)) {
// no self-loops, no parallel edges
if (scc[v] != scc[w]) {
ePrime.add(new SimpleImmutableEntry<>(scc[v], scc[w]));
}
}
}
kernelDag = new Digraph(vPrime.size());
for (Map.Entry<Integer, Integer> e : ePrime) kernelDag.addEdge(e.getKey(), e.getValue());
}

public int reachableFromAllOther() {
for (int v = 0; v < kernelDag.V(); v++) {
if (kernelDag.outdegree(v) == 0) return v;
}
return -1;
}

// reverse postorder
private void visit(int v) {
marked[v] = true;

for (int w : r.adj(v)) {
if (!marked[w]) visit(w);
}
s.push(v);
}

private void visit(int v, int i) {
scc[v] = i;

for (int w : g.adj(v)) {
if (scc[w] == -1) visit(w, i);
}
}
}

在下图中运行它会产生如图所示的强连接组件。减少的 DAG 中的顶点 0 可以从所有其他顶点到达。 enter image description here

我在任何地方都找不到的是上面介绍的那种详细信息。诸如“好吧,这很容易,你做那个,然后你做其他事情”之类的评论到处都是,没有具体的细节。

关于algorithm - 如何将强连通分量减少到一个顶点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51008611/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com