非再帰DFS

PyPy では深い再帰が遅く、スタックあふれも起きやすいので、スタックで DFS を書きます。帰りがけのタイミングを知るために、頂点 $v$ の訪問時にスタックへ ~v( $= -v-1$)を積んでおき、それを取り出したときを帰りがけとします。

コード中の「行きがけの処理」「帰りがけの処理」の位置に処理を書き足して使うこともできます。木 DP なら、帰りがけの処理で par[v] に $v$ の値を集めます。

コード

def dfs(g, s):
    n = len(g)
    seen = [False] * n
    par = [-1] * n
    pre = []
    post = []
    st = [s]
    while st:
        v = st.pop()
        if v >= 0:
            if seen[v]:
                continue
            seen[v] = True
            pre.append(v)
            # 行きがけの処理
            st.append(~v)
            for to in reversed(g[v]):
                if not seen[to]:
                    par[to] = v
                    st.append(to)
        else:
            v = ~v
            post.append(v)
            # 帰りがけの処理
    return pre, post, par