【问题标题】:Find a vertex that all other vertices can be reached from in a digraph在有向图中找到所有其他顶点都可以到达的顶点
【发布时间】:2020-05-05 20:31:55
【问题描述】:

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

如果我们要检查给定的顶点,我知道该怎么做;我们可以在反向图上做 dfs。但是对于这个问题,对图中的每个顶点都做这件事似乎效率很低。

有没有更好的办法?

【问题讨论】:

  • 在密集图上,你可以做一个 Floyd-Warshall,然后寻找一排所有的。
  • 这个问题有用吗? math.stackexchange.com/questions/99237
  • @Jake 是帖子要求可以从所有其他顶点到达的顶点(如标题所暗示的那样)或可以到达所有其他顶点的顶点(如帖子本身) ?
  • 一个可以到达其他所有顶点的顶点

标签: algorithm graph


【解决方案1】:

使用Kosaraju's algorithm及时查找图的强连通分量O(|V|+|E|)。如果您随后将每个组件“缩小”到单个节点,您将得到一个有向无环图。存在一个顶点,当且仅当 DAG 中恰好有一个入度为 0 的顶点时,可以从该顶点到达所有其他顶点。这就是您要寻找的顶点 - 所谓的“母顶点”。

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

【讨论】:

  • 最多一个顶点还是正好一个顶点?
  • 你是对的,完全是一个 - 如果图形没有度数为零的顶点,它将包含一个循环。已编辑。
  • 不是迂腐,但你的意思是“度数为 0”而不是“度数为 0”:) 很好的答案,已经投票了。
  • 不是吗?除非我遗漏了什么,否则绝对是零度数。
  • 认为是我糊涂了所以忽略上面的。但不是因为不好的原因而感到困惑。标题说:找到所有其他顶点都可达的顶点。
【解决方案2】:

可以通过从 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)时间。

【讨论】:

  • 如果我们有一个包含三个节点(比如 1、2 和 3)的图;和 1 和 2 连接,而 3 没有任何传入/传出边缘。您的第一个 for 循环将具有 moder_vertex=3 并且还将标记所有三个已访问(或已标记)的边。然后第二个 for 循环不会返回 false。最后,我们将得到不正确的 mother_index=3。是不是!
【解决方案3】:

我刚刚发明了以下算法。

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

这个想法是,由于任何顶点都应该可以从母顶点到达,我们可以沿着任意路径向上走,直到我们不能走得更高。

这样我们只检查可以到达起始顶点的强连通分量。在有很多入度为 0 的强连通分量的情况下,这将比 Andy 的算法有明显的优势。

【讨论】:

    【解决方案4】:
    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);
    
    
                }
    
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 1970-01-01
      • 2015-07-04
      • 1970-01-01
      相关资源
      最近更新 更多