快速查看边缘对于图形连接是否重要的​​方法

时间:2015-04-24 19:39:07

标签: c++ performance graph breadth-first-search undirected-graph

我有一组边E,我想知道我是否可以安全地删除E中的边i,这意味着如果我从图中删除它,图表仍应连接。

在我的理解中,暗示边缘i,必须躺在一个圆圈上。 输出应该是我无法删除的所有边的索引列表。

问题:

我的不同解决方案似乎做得对,但速度太慢(效率低下)。

我的一个解决方案是:

+

这种方式太慢了。

然后我决定重写我的代码并使用广度优先搜索来查看是否有可能没有边缘i的其他路径。

我认为它足够高效,但似乎并非如此。我要么以非常糟糕的方式实施,要么也是这项任务的错误算法。

这是我所拥有的C ++代码中的算法(删除了一些不重要的部分):

1. Loop through all edges i in E
  2. Loop through all edges x in V
    3. Add edge x to the graph (excluding edge i) until nodes of i are connected or end reached
  4. If no connection possible, edge is not removable and added to the list

你知道我的任何解决方案让它更快,或者你知道一个更好的算法来解决我的问题吗?

3 个答案:

答案 0 :(得分:1)

以下是您的算法的另一个版本(我想您将获得免费的图形和各种算法的行业标准优化实现):

我将此图像称为图形模型。 要点(来自post

  1. 找到清晰点
  2. 单个边缘的所有点都是 关节点(提升图不会返回这些) - 这些边缘 是自动桥接边缘
  3. 每个关节点 - 如果outedge已经没有桥接边缘那么循环在每个outed上 删除边缘并检查图形组件并添加边缘 再次
  4. 最后它将打印 Edge(a,g)连接图表中的组件

    enter image description here

    #include <iostream>
    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/biconnected_components.hpp>
    #include <boost/graph/connected_components.hpp>
    
    #include <functional>
    #include <string>
    #include <vector>
    #include <unordered_map>
    #include <unordered_set>
    
    typedef boost::adjacency_list <boost::vecS, boost::vecS, boost::undirectedS> Graph;
    typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
    typedef boost::graph_traits<Graph>::edge_descriptor edge_t;
    
    //  reference:
    //  http://lists.boost.org/boost-users/2005/08/13098.php
    //
    struct edge_t_hasher
    {
        std::size_t operator()(const edge_t& e) const
        {
            auto prop = e.get_property();
            std::hash<decltype(prop)> hasher;
            return hasher(prop);
        }
    };
    
    typedef std::unordered_set<edge_t, edge_t_hasher> UnorderedBoostEdgeSet;
    
    Graph getGraph()
    {
        Graph g;
    
        vertex_t aVtx = boost::add_vertex(g);
        vertex_t bVtx = boost::add_vertex(g);
        vertex_t cVtx = boost::add_vertex(g);
        vertex_t dVtx = boost::add_vertex(g);
        vertex_t eVtx = boost::add_vertex(g);
        vertex_t fVtx = boost::add_vertex(g);
        vertex_t gVtx = boost::add_vertex(g);
        vertex_t hVtx = boost::add_vertex(g);
        vertex_t iVtx = boost::add_vertex(g);
    
        boost::add_edge(dVtx, cVtx, g);
        boost::add_edge(dVtx, bVtx, g);
        boost::add_edge(cVtx, bVtx, g);
        boost::add_edge(aVtx, bVtx, g);
        boost::add_edge(bVtx, eVtx, g);
        boost::add_edge(eVtx, fVtx, g);
        boost::add_edge(aVtx, fVtx, g);
        boost::add_edge(aVtx, gVtx, g);// edge connecting components
        boost::add_edge(gVtx, iVtx, g);
        boost::add_edge(gVtx, hVtx, g);
        boost::add_edge(hVtx, iVtx, g);
    
        return g;
    }
    
    UnorderedBoostEdgeSet bridgingEdgesForGraph(const Graph& graph)
    {
        UnorderedBoostEdgeSet bridgeEdges;
    
        std::unordered_set<vertex_t> articulationVertices;
        boost::articulation_points(graph, std::inserter(articulationVertices, articulationVertices.end()));
    
        //  add all the single connected vertices to the articulation vertices
        auto vtxIters = boost::vertices(graph);
        for (auto it = vtxIters.first, end = vtxIters.second; it != end; ++it)
        {
            if (boost::out_degree(*it, graph) == 1)
                bridgeEdges.insert(*(boost::out_edges(*it, graph).first));
        }
    
        std::vector<vertex_t> componentsInGraph(boost::num_vertices(graph));
        int numComponentsInGraph = boost::connected_components(graph, &componentsInGraph[0]);
    
        //  for each articulation vertex now get edges and check if removing that
        //  edge causes graph change in connected components
        //
    
        //  copy the graph- so we can iterate over the outeges of vertices
        //  we will be fiddling with the copy- since the vtx descriptors are
        //  ints- they stay same across copy and removing edge operation
        auto graph2 = graph;
        for (auto vtx : articulationVertices)
        {
            auto outEdges = boost::out_edges(vtx, graph);
            for (auto it = outEdges.first, end = outEdges.second; it != end; ++it)
            {
                auto edge = *it;
                if (bridgeEdges.find(edge) != bridgeEdges.end())
                    continue;
    
                //  map this edge to graph2 edge- for removal and eventual addition
                auto src = boost::source(edge, graph);
                auto tgt = boost::target(edge, graph);
    
                auto edge2 = boost::edge(src, tgt, graph2).first;
    
                boost::remove_edge(edge2, graph2);
                std::vector<vertex_t> componentsInGraph2(boost::num_vertices(graph2));
                int numComponentsInGraph2 = boost::connected_components(graph2, &componentsInGraph2[0]);
    
                // bridging edge- graph #components changed
                if (numComponentsInGraph != numComponentsInGraph2)
                    bridgeEdges.insert(edge);
    
                //  add the edge back to graph2
                boost::add_edge(src, tgt, graph2);
            }
        }
    
        return bridgeEdges;
    }
    
    int main()
    {
        const Graph& graph = getGraph();
        const auto& bridgingEdges = bridgingEdgesForGraph(graph);
    
        const char* array = {"ABCDEFGHI"};
        for (auto edge : bridgingEdges)
        {
            std::cout << "Edge(" << array[boost::source(edge, graph)] << ", " << array[boost::target(edge, graph)] 
                      << ") is a bridging edge" << std::endl;
        }
    
        return 0;
    }
    

答案 1 :(得分:1)

删除断开两个连接组件的边缘称为 bridge ,并且有线性时间算法用于查找图中的所有桥(通常基于深度优先搜索) 。维基百科的文章列出了其中一个(由于Tarjan)作为一个例子。 This paper还提供了一个简单的算法,用于列出图中的所有桥,并且似乎比Tarjan的算法更简单。

希望这有帮助!

答案 2 :(得分:0)

与此同时,我发现了这些特殊边缘是如何被称为:桥梁。

因此我找到了一个网站,提供了一个DFS算法来查找所有网桥。

这对我的目的来说足够快。

DFS algorithm for finding Bridges in a undirected Graph

谢谢Sarang,你的帖子让我找到了网站的正确搜索词。