码迷,mamicode.com
首页 > 其他好文 > 详细

Tarjan

时间:2021-05-24 02:15:52      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:缩点   stream   head   read   target   pen   for   模板   http   

有向图强连通分量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;
}

Tarjan

标签:缩点   stream   head   read   target   pen   for   模板   http   

原文地址:https://www.cnblogs.com/DReamLion/p/14746432.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!