如何在无向图中找到桥?

Jak*_*old 2 algorithm graph undirected-graph

给定一个无向图,我怎样才能找到所有的桥?我只发现Tarjan的算法看起来相当复杂.

似乎应该有多个线性时间解决方案,但我找不到任何东西.

Nik*_*nka 7

Tarjan算法是无线图中第一个以线性时间运行的桥寻找算法.但是,存在一个更简单的算法,您可以在此处查看其实现.

    private int bridges;      // number of bridges
    private int cnt;          // counter
    private int[] pre;        // pre[v] = order in which dfs examines v
    private int[] low;        // low[v] = lowest preorder of any vertex connected to v

    public Bridge(Graph G) {
        low = new int[G.V()];
        pre = new int[G.V()];
        for (int v = 0; v < G.V(); v++) low[v] = -1;
        for (int v = 0; v < G.V(); v++) pre[v] = -1;

        for (int v = 0; v < G.V(); v++)
            if (pre[v] == -1)
                dfs(G, v, v);
    }

    public int components() { return bridges + 1; }

    private void dfs(Graph G, int u, int v) {
        pre[v] = cnt++;
        low[v] = pre[v];
        for (int w : G.adj(v)) {
            if (pre[w] == -1) {
                dfs(G, v, w);
                low[v] = Math.min(low[v], low[w]);
                if (low[w] == pre[w]) {
                    StdOut.println(v + "-" + w + " is a bridge");
                    bridges++;
                }
            }

            // update low number - ignore reverse of edge leading to v
            else if (w != u)
                low[v] = Math.min(low[v], pre[w]);
        }
    }
Run Code Online (Sandbox Code Playgroud)

该算法通过维持2个数组前置和下行来完成工作.pre保存节点的预订遍历编号.所以pre [0] = 2表示在第3次dfs调用中发现了顶点0.而low [u]保存从u可到达的任何顶点的最小预订数.

该算法在边缘u-v时检测到​​一个桥,其中u在预编号中首先出现,低[v] == pre [v].这是因为如果我们删除u - v之间的边缘,则v无法到达u之前的任何顶点.因此,移除边缘会将图形拆分为2个单独的图形.

有关更详细的解释,您还可以查看此答案.