图 - 查找从所有其他顶点可到达的顶点

时间:2014-01-05 20:22:07

标签: algorithm graph

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

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

有更好的方法吗?

感谢。

4 个答案:

答案 0 :(得分:11)

使用Kosaraju's algorithm及时查找图表中强关联的组件O(|V|+|E|)。如果然后将每个组件“缩小”到单个节点,则会留下有向非循环图。存在一个顶点,当且仅当DAG中有一个具有in-degree 0的顶点时,才能到达所有其他顶点。这是您正在寻找的顶点 - 所谓的“母顶点”。

注意:这个答案最初建议使用Tarjan的算法。 Tarjan的速度可能会快一些,但它也比Kosaraju的复杂一点。

答案 1 :(得分:3)

通过采用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);
}

上述算法需要O(V + E)时间来解决问题。

答案 2 :(得分:1)

我刚刚发明了以下算法。

  • 从任意顶点开始,并将其标记为“已访问”。
  • 将图表中的“向上”移至任意父顶点,并将其标记为“已访问”。
  • 跟踪堆栈上的访问顶点。
  • 如果到达没有父顶点的顶点,请检查它是否确实是可以到达所有其他顶点的顶点。
  • 到达已访问的顶点V时:
    1. 不要将访问的顶点V添加到堆栈。将前一个顶点标记为强连接组件的“结束”。
    2. 沿堆栈向下,直到到达已经访问过的顶点V. 在此过程中,您将删除所有“结束”和“开始”标记。 如果删除的最后一个标记是“开始”标记,则将V标记为“开始”,否则不标记。
    3. 再次从堆栈顶部开始向下,直到找到一个带有未访问父项的顶点(并继续执行算法的第一步)或直到你到达标记为'start'的顶点并检查它是否为确实是一个母亲顶点,其他所有人都可以到达。

这个想法是,因为任何顶点都应该可以从母顶点到达,所以我们可以向上采取任意路径,直到我们不能更高。

这样我们只检查可以到达起始顶点的强连通分量。如果有很多强连通组件的度数为0,那么这将是Andy算法的明显优势。

答案 3 :(得分:0)

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);


            }

        }

    }
}