Algorithm 在有向图中查找可以到达所有其他顶点的顶点

Algorithm 在有向图中查找可以到达所有其他顶点的顶点,algorithm,graph,Algorithm,Graph,给定一个有向图,我们如何确定是否存在一个顶点v,所有其他顶点都可以从该顶点v到达。算法应该尽可能高效 我知道如何做,如果我们正在检查一个给定的顶点;我们可以在反向图上进行dfs。但对于这个问题,对图中的每个顶点都这样做似乎效率低下 有更好的方法吗?用于在时间O(|V|+|E|)中查找图的强连通分量。如果将每个组件“收缩”到一个节点,则将留下一个有向无环图。存在一个顶点,当且仅当DAG中只有一个顶点的阶数为0时,可以从该顶点到达所有其他顶点。这是您正在寻找的顶点-所谓的“母顶点” 注:此答案最初建

给定一个有向图,我们如何确定是否存在一个顶点v,所有其他顶点都可以从该顶点v到达。算法应该尽可能高效

我知道如何做,如果我们正在检查一个给定的顶点;我们可以在反向图上进行dfs。但对于这个问题,对图中的每个顶点都这样做似乎效率低下

有更好的方法吗?

用于在时间
O(|V|+|E|)
中查找图的强连通分量。如果将每个组件“收缩”到一个节点,则将留下一个有向无环图。存在一个顶点,当且仅当DAG中只有一个顶点的阶数为0时,可以从该顶点到达所有其他顶点。这是您正在寻找的顶点-所谓的“母顶点”


注:此答案最初建议使用Tarjan算法。Tarjan的可能要快一点,但也比Kosaraju的要复杂一点

我刚刚发明了以下算法

  • 从任意顶点开始,并将其标记为“已访问”
  • 在图中“向上”转到任意父顶点,并将其标记为“已访问”
  • 跟踪堆栈上访问的顶点
  • 如果到达的顶点没有父顶点,请检查它是否确实是所有其他顶点都可以从中到达的顶点
  • 到达已访问的顶点V时:
  • 不要将访问的顶点V添加到堆栈中。将上一个顶点标记为强连接组件的“端点”
  • 沿着堆栈向下移动,直到到达已访问的顶点V。 一路上,您可以删除所有“结束”和“开始”标记。 如果最后移除的标记是“开始”标记,则将V标记为“开始”,否则不要标记
  • 再次从堆栈顶部开始向下移动,直到找到具有未访问父顶点的顶点(并继续执行算法的第一步),或者直到到达标记为“开始”的顶点,并检查该顶点是否确实是可以访问所有其他顶点的母顶点
这个想法是,因为任何顶点都应该可以从母顶点到达,所以我们可以沿着任意的路径向上走,直到我们不能再往上走


这样,我们只检查可以到达起始顶点的强连接组件。如果存在大量阶数为0的强连通组件,这将是Andy算法的一个明显优势。

可以从Kosaraju的强连通组件算法中找到解决方案。这一想法基于以下事实:

如果存在一个顶点(或多个顶点),所有其他顶点都可以从该顶点到达,则该顶点在DFS遍历中的完成时间最长。 因此,解决方案如下所示:

// Utility function to find mother vertex 
//(vertex from which all other vertices are reachable)

public void findMotherVertex() {
    int motherVertex=0;

    for (int i=0;i<G.V();i++) {  //G.V() would return the no. of vertices in the graph
        if (!marked[i]) {  //marked - boolean array storing visited vertices
            dfs(i);
            motherVertex=i;
        }
    }

    //Check for this vertex if all other vertices have been already visited
    //Otherwise no mother vertex exists

    for (int i=0;i<G.V();i++) {
        if (!marked[i])
            return false;
    }

    System.out.println("Desired vertex is : " + motherVertex);
}
//查找母顶点的实用函数
//(所有其他顶点均可从中访问的顶点)
public void findMotherVertex(){
int=0;
对于(inti=0;i
importjava.util.*;
公共类FindMotherVertex{
公共静态void main(字符串[]arg){
List edges=Arrays.asList(
新边(0,1),新边(0,2),
新边(1,3),
新边(4,1),
新边(5,2),新边(5,6),
新边(6,4),
新边(6,0)
);
findMotherVertex(图);
}
公共静态void findMotherVertex(图形){
int=0;
布尔值[]已访问=新布尔值[7];
对于(int i=0;i=0;i--){
int u=list.get(i);
如果(!访问[u]);
堆栈推送(u);
}
}
}
静态类图{
//表示辅助列表的列表列表列表
List adj=新的ArrayList();
//构造图的构造函数
公共图(列出边){
//为邻接列表分配内存
对于(int i=0;i
在稠密图上,你可以做一个Floyd Warshall,然后查找一行所有的。这个问题有用吗?@Jake是一篇帖子,要求一个可以从其他每个顶点到达的顶点(如标题所示),或者一个可以从其他每个顶点到达的顶点(如帖子本身)?一个顶点,每个其他顶点最多可以到达一个顶点,或者正好可以到达一个顶点?你是对的,正好是一个-如果图中没有处于零度的顶点,它将包含一个循环。编辑。不是学究式的,但你的意思是“没有处于0度”而不是“处于0度”):答案很好,已经投了赞成票。不是吗?除非我遗漏了什么,否则绝对是零度。认为是我感到困惑,所以忽略上面的内容。但困惑并不是因为一个坏的原因。标题是:找到所有其他顶点都可以到达的顶点;和1和2是连接的,而3没有任何传入/传出边。您是第一个使用moder_vertex=3的for循环,并且还将标记所有访问(或标记)的三条边。那么第二个for循环将不会返回false。最后,我们将得到母亲指数=3,这是不正确的。不是吗!
import java.util.*;

public class FindMotherVertex {
    public static void main(String[] arg) {
        List<Edges> edges = Arrays.asList(
            new Edges(0, 1), new Edges(0, 2),
            new Edges(1, 3),
            new Edges(4, 1),
            new Edges(5, 2), new Edges(5, 6),
            new Edges(6, 4),
            new Edges(6, 0)
        );
        findMotherVertex(graph);

    }
    public static void findMotherVertex(Graph graph) {
        int motherVertex =  0;
        boolean[] visited = new boolean[7];

        for (int i=0;i<7;i++) {  
            if (visited[i] == false) {  //marked - boolean array storing visited vertices
                DFS(graph,i,visited);
                motherVertex= i;
            }

        }

        //Check for this vertex if all other vertices have been already visited
        //Otherwise no mother vertex exists

        for (int i=0;i<6;i++) {
            if (!visited[i]){ visited[i] = false;}

        }

        System.out.println("Mother vertex is : " + motherVertex);
    }

    public static void DFS(Graph graph, int v,boolean[] visited) {

        //create a stack used to do DFS
        Stack<Integer> stack = new Stack<>();
        stack.add(v);
        //Run While queue is empty

        while (!stack.isEmpty()) {
            //Pop vertex from stack
            v = stack.pop();

            if (visited[v])
                continue;
            visited[v] = true;
            System.out.print("(" + v + ")" + "===>");
// do for every edge
            List<Integer> list = graph.adj.get(v);
            for (int i = list.size() - 1; i >= 0; i--) {
                int u = list.get(i);
                if (!visited[u]) ;
                stack.push(u);
            }
        }

    }


    static class Graph {

        //List of List to represent Adajacency List
        List<List<Integer>> adj = new ArrayList<>();
        //Constructor to construct Graph

        public Graph(List<Edges> edges) {
            //Allocate memory for adjacency List
            for (int i = 0; i < edges.size(); i++) {
                adj.add(i, new ArrayList<>());
            }

            //Add edges to the undirected Graph
            for (Edges curr : edges) {
                adj.get(curr.src).add(curr.desc);


            }

        }

    }
}