zoukankan      html  css  js  c++  java
  • Tarjan

    有向图强连通分量SCC

    P3387【模板】缩点
    注释放代码里啦
    时间复杂度O(n+m)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 100010
    #define maxm 1000010
    using namespace std;
    template<typename T>
    inline void read(T &x){
        x=0;bool flag=0;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
        for(;isdigit(c);c=getchar()) x=x*10+(c^48);
        if(flag) x=-x;
    }
    
    int n,m,w[maxn],x[maxm],y[maxm];//因为重新建图还要用到,所以x,y要拿数组存 
    int cnt,head[maxn];
    int dfn[maxn],low[maxn],co[maxn],v[maxn],val[maxn];//dfn时间戳,low追溯值
    int top,st[maxn],siz[maxn],f[maxn],ans,dfncnt,cocnt;//st栈,f记搜 
    bool vis[maxn];//判断该点在不在栈中 
    struct node{
        int nxt;
        int to;
    }e[2*maxn];
    
    void add(int from,int to){
        e[++cnt].to=to;
        e[cnt].nxt=head[from];
        head[from]=cnt;
    }
    
    void tarjan(int x){
        dfn[x]=low[x]=++dfncnt;
        st[++top]=x;
        vis[x]=1;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else{
                if(vis[y]) low[x]=min(low[x],dfn[y]);//********
            }
        }
        if(low[x]==dfn[x]){
            cocnt++;//cocnt记录整张图的强连通分量个数 
            int now;
            do{
                now=st[top];
                top--;
                vis[now]=0;
                co[now]=cocnt;//co[now]表示now所在的强连通分量编号 
                val[cocnt]+=v[now];
            }while(now!=x);
        }
    }
    
    void clear(){
        cnt=0;
        for(int i=1;i<=m;i++) head[i]=0,e[i].nxt=0,e[i].to=0;
    }
    
    void dfs(int x){//在DAG上记忆化搜索 
        if(f[x]) return ;
        f[x]=val[x];
        int maxx=0;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!f[y]) dfs(y);
            maxx=max(maxx,f[y]);
        }
        f[x]+=maxx;
    }
    
    int main(){
        read(n),read(m);
        for(int i=1;i<=n;i++) read(v[i]);
        for(int i=1;i<=m;i++) read(x[i]),read(y[i]),add(x[i],y[i]);//建原图 
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        clear();//把原图清空 
        for(int i=1;i<=m;i++) if(co[x[i]]!=co[y[i]]) add(co[x[i]],co[y[i]]);//重新建图,如果这条边的两点不在一个强连通分量里,就连上这条边 
        for(int i=1;i<=cocnt;i++){
            if(!f[i]) dfs(i);
            ans=max(ans,f[i]);
        }
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14746432.html
Copyright © 2011-2022 走看看