在没有递归的情况下在图中查找桥

时间:2014-04-20 07:23:52

标签: algorithm recursion graph

我有这个代码来查找连接图中的桥:

void dfs (int v, int p = -1) {
    used[v] = true;
    tin[v] = fup[v] = timer++;
    for (size_t i=0; i<g[v].size(); ++i) {
        int to = g[v][i];
        if (to == p)  continue;
        if (used[to])
            fup[v] = min (fup[v], tin[to]);
        else {
            dfs (to, v);
            fup[v] = min (fup[v], fup[to]);
            if (fup[to] > tin[v])
                printf("%d %d", v, to);
        }
    }
}

如何在不使用递归的情况下重写它?我知道,它可以这样做,我应该使用堆栈,但是这行必须在递归调用dfs()之后执行,而我无法通过堆栈实现:

fup[v] = min(fup[v], fup[to])

那么,如何迭代地重写我的算法呢?

2 个答案:

答案 0 :(得分:4)

您想制作“堆叠框架”结构

struct Frame {
    Frame(int v, int p, int i, Label label);
    int v;
    int p;
    int i;
};

// constructor here

并且,如你所说,stack<Frame>。在所有这些字段之间,可以模拟调用堆栈(未经测试的代码以提供一般概念)。

void dfs(int v, int p = -1) {
  stack<Frame> st;
  st.push(Frame(v, p, 0));
  do {
    Frame fr(st.top());
    st.pop();
    v = fr.v;
    p = fr.p;
    int i(fr.i);
    if (i > 0) {
      int to(g[v][i - 1]);
      fup[v] = min(fup[v], fup[to]);
      if (fup[to] > tin[v]) { printf("%d %d", v, to); }
      if (i == g[v].size()) { continue; }
    } else if (i == 0) {
      used[v] = true;
      tin[v] = fup[v] = timer++;
    }
    int to(g[v][i]);
    if (to == p) { continue; }
    if (used[to]) {
       fup[v] = min(fup[v], tin[to]);
    } else {
       st.push(Frame(to, v, 0));
    }
    st.push(Frame(v, p, i + 1));
  } while (!st.empty());
}

答案 1 :(得分:0)

对不起,我晚答复了。

更改先前答案的代码,现在可以正常使用了。 在竞赛任务中进行了测试,以查找连接的Graph中的所有桥。 希望对您有帮助。

// Copyright 2020 Kondratenko Evgeny
#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>


struct Frame {
    Frame(int v, int p, int i) : v(v), p(p), i(i) {
    }
    int v;
    int p;
    int i;
};


void DFS(int n,
        const std::vector<std::vector<int>> &G,
        const std::vector<std::vector<int>> &weights) {
    std::vector<bool> used(n + 1, false);
    std::vector<int> ret(n + 1);  // the same as tup
    std::vector<int> enter(n + 1);  // the same as tin
    std::stack<Frame> s;
    s.push(Frame(1, -1, 0));
    int time = 1;
    while (!s.empty()) {
        Frame f = s.top();
        s.pop();
        int v = f.v;
        int p = f.p;
        int i = f.i;
        if (i == 0) {
            enter[v] = ret[v] = time++;
            used[v] = true;
        }
        // First part works befor DFS call
        if (i < G[v].size()) {
            int to = G[v][i];
            s.push(Frame(v, p, i + 1));
            if (to != p) {
                if (used[to]) {
                    ret[v] = std::min(ret[v], enter[to]);
                } else {
                    s.push(Frame(to, v, 0));
                }
            }
        }
        /*
            Generally here is virtual DFS recursive call, which we are simulate now
        */
        // Second part after DFS call
        if (i > 0 && i <= G[v].size()) {
            int to = G[v][i - 1];
            if (to != p) {
                ret[v] = std::min(ret[v], ret[to]);
                if (ret[to] > enter[v]) {
                    std::cout << "bridge between: " << v << " and " << to;
                    std::cout << ", with weight: " << weights[v][i - 1] << std::endl;
                }
            }
        }
    }
}


int main() {
    int n, m;  // n - number of vertex, m - number of edges
    std::cin >> n >> m;
    std::vector<std::vector<int>> G(n + 1, std::vector<int>());  // your Graph
    std::vector<std::vector<int>> weights(n + 1, std::vector<int>());
    for (int i = 0; i < m; ++i) {  // read edges with weigths
        int u, v, w;
        std::cin >> u >> v >> w;
        G[u].push_back(v);
        G[v].push_back(u);
        weights[u].push_back(w);
        weights[v].push_back(w);
    }
    DFS(n, G, weights);
    return 0;
}