有向图中有多少个组件?

时间:2015-06-30 11:53:05

标签: graph

我有以下图表:

directed graph http://i62.tinypic.com/sx2hqc.png

最佳解决方案是从顶点(3)启动dfs然后我将获得一个组件,但是当我们从顶点(1)启动dfs然后(3)我将得到两个组件。 问题是: 我想知道这个图表中有多少个组件?或者换句话说,覆盖所有图表所需的最小dfs数量是多少?

执行此操作所需的算法是什么?

7 个答案:

答案 0 :(得分:0)

你混淆了两个定义。

对于无向图,有connected components的概念,您可以通过在无向图上执行DFS找到它。

对于有向图,有strongly connected components的概念,有多种算法可用,所有算法都比简单的DFS稍微复杂一些。

您应该做什么取决于您需要的两个概念中的哪一个。您的图表在被视为无向图时具有一个连接的组件,在被视为有向图时具有两个强连接的组件。

答案 1 :(得分:0)

为解决此问题,我们的想法是处理IN边缘的邻接列表。

以具有3个节点和2个边线(0,1)和(0,2)的图为例,而(a,b)表示如果您切换光源a,那么光源b也将被切换。 / p>

OUT-edges adjacency list:
0 -> 1, 2
1 -> _
2 -> _

IN-edges adjacency list:
0 -> _
1 -> 0
2 -> 0

假设我们没有周期,如果我们沿着IN边缘向下移动,直到到达没有孩子的节点,您就会得到我所谓的“影响者”,也就是说,您无法使用任何其他节点。

现在要考虑周期问题,我将检查是否有邻居或有影响者。如果不是这种情况,并且所有邻居都已被访问过,那么我会遇到一个循环并使当前节点成为影响者。

这是我的代码(在我的办公桌上通过简单的示例进行了测试):

private int numberOfLights(){

    Scanner scanner = new Scanner(System.in);
    int n = scanner.nextInt();

    List<List<Integer>> inAdjList = new ArrayList<List<Integer>>();
    for(int i = 0; i < n; i++){
        inAdjList.add(new ArrayList<>());
    }


    for(int i = 0; i < n; i++){
        int from = scanner.nextInt();
        int to = scanner.nextInt();

        inAdjList.get(to).add(from);
    }

    int[] visited = new int[n];
    int[] isOrHasInfluencer = new int[n];
    List<Integer> influencers = new ArrayList<>();

    for(int i = 0; i < n; i++){
        if(!visited[i]){
            DFS(i, visited, isOrHasInfluencer, influencers, inAdjList);
        }
    }

    return influencers.size();

}

private void DFS(Integer cur, int[] visited, int[] isOrHasInfluencer, List<Integer> influencers, List<List<Integer>> inAdjList){

    visited[cur] = true;

    boolean hasUnvisitedChildren = false;
    for(Integer neighbor : inAdjList.get(cur)){

        if(!visited[neighbor]){
            hasUnvisitedChildren = true;
            DFS(neighbor, visited, isOrHasInfluencer, influencers, inAdjList);
        }

        if(isOrHasInfluencer[neighbor]){
            isOrHasInfluencer[cur] = true;
        }
    }

    if(!hasUnvisitedChildren && !isOrHasInfluencer[cur]){
        isOrHasInfluencer[cur] = true;
        influencers.add(cur);
    }
}

希望有帮助! :)

答案 2 :(得分:0)

您可以从每个节点运行findConnectedComponent算法,并返回最小数目以解决您的特定问题。 我认为该解决方案不是最佳解决方案,但对中小型输入图效果很好。

答案 3 :(得分:0)

我为这个问题奋斗了数周 最终,当我在Codechef的一场编码比赛中遇到一个问题时,找到了解决方案。

解决过程:

  • 执行拓扑排序,然后在获得的排序结果上执行DFS。您必须调用DFS的次数就是连接的组件数。

在您的情况下,进行拓扑排序后,我们得到3 1 2 4 现在再次根据排序后的值运行DFS(此处以3开头),您将获得ans 1。

希望有帮助:)

答案 4 :(得分:0)

我相信您正在尝试找到弱连接的组件。 测试有向图是否弱连接很容易在线性时间内完成。只需将所有边缘变成无方向的边缘,然后使用基于DFS的连接组件算法即可。

答案 5 :(得分:0)

我知道这是一个旧线程,但添加我如何解决问题会很有帮助:

1 - 找到图中的强连通分量 (SCC),对于每个 SCC,我们可以用代表该 SCC 的单个节点替换它。

2 - 现在,通过查看新图中节点的度数,我们可以知道可以从中运行 DFS 并覆盖所有其他节点的最小节点数,因此我们可以从具有 <强>度数为零。

答案 6 :(得分:0)

老问题,但还有另一种方法。

  1. 通过在所有节点上执行 DFS 将有向图转换为无向图。 O(V+E)
  2. 做你对无向图所做的事情。 O(V+E)