模板 两次dfs

第一次dfs为后序遍历
第二次dfs将所有边反向,从编号最大的顶点开始(也就是原图缩点后形成的DAG根节点所在的强连通分量),由于边反向后,不能由这个强连通分量访问到其他强连通分量的顶点,而强连通分量内部之间的顶点不受影响,所以每一次dfs所遍历到的所有顶点形成一个强连通分量
通过这种算法得到的强连通分量的编号表示DAG上的一种拓扑序
算法进行了两次dfs,时间复杂度\(O(|V|+|E|)\)

const int maxn=10010,maxm=50010;
int n,m,head[maxn],nxt[maxm],to[maxm],cnt=1;
int rhead[maxn],rnxt[maxm],rto[maxm];
int book[maxn],comp[maxn];
vector<int> vs;

void dfs(int u){
    book[u]=1;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(!book[v]) dfs(v);
    }  
    vs.push_back(u);
}

void rdfs(int u,int k){
    book[u]=1;
    comp[u]=k;
    for(int i=rhead[u];i;i=rnxt[i]){
        int v=rto[i];
        if(!book[v]) rdfs(v,k);
    }
}

int scc(){
    memset(book,0,sizeof(book));
    vs.clear();
    for(int i=0;i<n;i++){
        if(!book[i]) dfs(i);
    }
    memset(book,0,sizeof(book));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(!book[vs[i]]) rdfs(vs[i],k++);
    }
    return k;
}
posted @ 2020-07-31 16:37  fxq1304  阅读(81)  评论(0)    收藏  举报