【问题标题】:Generate a Connected Graph java生成连通图 java
【发布时间】:2018-10-27 04:49:03
【问题描述】:

我想编写一个函数,给定一组顶点,然后在 2 个顶点之间形成一条边,并重复此操作,直到图成为连通图)。如何判断图表何时已连接?

【问题讨论】:

  • 我不确定我是否理解这个问题。您能发布到目前为止您尝试过的内容吗?
  • 边缘应该是有向的还是无向的?要添加的边数是否限制在一定数量?
  • 我们需要更多信息...但是,您可以使用 Dijkstra 算法检查图是否已连接:如果到最后您仍然有一个距离为 +inf 的节点,则它未连接还没有。
  • 作为您可以开发的数据结构,您可以使用邻接表向量,通过将节点的对应边添加一个数组来表达节点与其他节点之间的关系。
  • 您应该研究“disjoint set”数据结构的变体,它通常用于图论应用程序中,用于跟踪图如何划分为连接的组件。这可以支持比替代方案更有效的算法,具体取决于用于检查节点连通性的图搜索。

标签: java random graph-theory


【解决方案1】:

这是一个基本想法:每次添加新边缘时,都会运行 BFS 或 DFS 来检查连通性。该解决方案可以进一步优化。

import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Random;
import java.util.Set;

import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.SimpleGraph;

public class Main {

public static boolean isConnected(SimpleGraph<Integer, DefaultEdge> graph) {
    Set<Integer> vertexSet = graph.vertexSet();
    if(vertexSet.size()==0) {
        //graph is connected by definition
        return true;
    }

    if(vertexSet.size()-1>graph.edgeSet().size()) {
        //not enough edges, must be disconnected
        return false;
    }

    Set<Integer> traversed = new HashSet<>();
    Deque<DefaultEdge> toTraverse = new LinkedList<DefaultEdge>();

    //pick one random element to start search
    Integer startVertex = vertexSet.iterator().next();

    traversed.add(startVertex);
    graph.edgesOf(startVertex).forEach(x->toTraverse.addLast(x));
    while(traversed.size()!=vertexSet.size() && toTraverse.size()!=0) {
        DefaultEdge currentEdge = toTraverse.pollFirst();
        Integer src = graph.getEdgeSource(currentEdge);
        Integer dst = graph.getEdgeSource(currentEdge);

        //it can be at most one new vertex
        Integer targetVertex = traversed.contains(src)?dst:src;
        if(!traversed.contains(targetVertex)) {
            traversed.add(targetVertex);
            //BFS
            graph.edgesOf(targetVertex).forEach(x->toTraverse.addLast(x));

            //DFS
            //graph.edgesOf(targetVertex).forEach(x->toTraverse.addFirst(x));
        }
    }

    if(traversed.size()==vertexSet.size()) {
        return true;
    }else {
        return false;
    }
}

public static SimpleGraph<Integer, DefaultEdge> buildGraph(int numberOfVertices) {
    SimpleGraph<Integer, DefaultEdge> g =
            new SimpleGraph<Integer, DefaultEdge>(DefaultEdge.class);
    for(int i = 0; i < numberOfVertices; i++) {
        g.addVertex(i);
    }
    Random r = new Random();
    do {
        int a = r.nextInt(numberOfVertices);
        int b = r.nextInt(numberOfVertices);
        while(a == b) {
            b = r.nextInt(numberOfVertices);
        }
        g.addEdge(a, b);
    }while(!isConnected(g));
    return g;

}

public static void main(String[] args) {
    SimpleGraph<Integer, DefaultEdge> g = buildGraph(10);
    System.out.println("Number of edges");
    System.out.println(g.edgeSet().size());
    System.out.println("Edges:");
    for(DefaultEdge e: g.edgeSet()){
        String a = g.getEdgeSource(e).toString();
        String b = g.getEdgeTarget(e).toString();
        System.out.println(a+" "+b);
    }
}

}

对于任意图,检查连通性至少需要 O(V)(V - 顶点数,E - 边数)。 BFS 和 DFS 在 O(V+E) 中运行。如果您想创建相对较小的图表,这可能很好。这是一个更聪明的想法。在开始时,您创建 V 个单独的图表。现在您要在 A 和 B 之间添加边,您会找到 A 所属的图形和 B 所属的另一个图形。如果这是两个不同的图表,请将它们合并。重复这个过程,直到只剩下一张图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2011-01-30
    • 2016-12-30
    相关资源
    最近更新 更多