tarjan求edcc vdcc

//求无向图:e-dcc(边双联通分量)
//重边的处理  e---e反
//low[x]>dfn[y],edge(x,y)才可以
//键图:belong[point]=edcc struct node { int fr,to,nxt; }e[N<<1]; int tot=1,head[N]; inline void add(int x,int y) { e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot; e[tot].fr=x; } int n,m; int dfn[N],dfn_cnt,belong[N],low[N],edcc; bool cut[N<<1]; inline void tarjan(int x,int lst_edge) { dfn[x]=low[x]=++dfn_cnt; for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; if(!dfn[to]) { tarjan(to,i); low[x]=min(low[x],low[to]); if(low[to]>dfn[x]) { cut[i]=cut[i^1]=1; } } else if(i!=(lst_edge^1))low[x]=min(low[x],dfn[to]); } } inline void dfs(int x) { belong[x]=edcc; for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; if(cut[i]||belong[to])continue; //这里belong!=0就不行,因为我只是要找哪个点是哪个edcc,访问过了就没有必要访问了 dfs(to); } } int main() { // freopen("exam.txt","r",stdin); // freopen("a.out","w",stdout); n=re(),m=re(); _f(i,1,m) { int u=re(),v=re(); add(u,v);add(v,u); } _f(i,1,n)if(!dfn[i])tarjan(i); _f(i,1,n) { if(!belong[i])edcc++,dfs(i); }//找出那个点属于哪些edcc _f(i,2,tot) { if(belong[e[i].fr]!=belong[e[i].to])Add(e[i].fr,e[i].to);//这就是新的图了 } return 0; }
//求无向图:-dcc(点双联通分量)
//根节点必2个special point (o--o)   dcc,x要留着    只要有,就放
//low[y]>=dfn[x]
//我每次判断找dcc时都是截止到这个儿子,所以每次tarjan一个儿子都要找一遍dcc
//如果有自环的话记得去掉否则单点算不上
struct node { int fr,to,nxt; }e[N<<1]; int tot=1,head[N]; inline void add(int x,int y) { e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot; e[tot].fr=x; } int n,m; int dfn[N],dfn_cnt,belong[N],low[N],edcc; vector<int>dcc[N]; int cnt;bool cut[N]; int stack[N],top; int root; void tarjan(int x) { dfn[x]=low[x]=++dfn_cnt; stack[++top]=x; if(x==root&&head[x]==0) { dcc[++cnt].push_back(x);return ; } int f=0; 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]); if(low[y]>=dfn[x]) { f++; if(f>1||x!=root)cut[x]=true; cnt++; int z=0; do { z=stack[top--]; dcc[cnt].push_back(z); }while(z!=y); dcc[cnt].push_back(x);//但是x还要留在stack里面 } } else low[x]=min(low[x],dfn[y]); } }int num; int main() { // freopen("exam.txt","r",stdin); // freopen("a.out","w",stdout); n=re(),m=re(); _f(i,1,m) { int u=re(),v=re(); add(u,v);add(v,u); } _f(i,1,n)if(!dfn[i])root=i,tarjan(i); num=cnt; for(int i=1;i<=cnt;i++) { if(cut[i])new_id[i]=++num; } tc=1; for(int i=1;i<=cnt;i++) { for(int j=0;j<dcc[i].size();j++) { int x=dcc[i][j]; if(cut[x]) { add_c(i,new_id[x]); add_c[new_id[x],i); } else c[x]=i; } } return 0; }

 

//求有向图:-(强双联通分量)
//在求scc时我要遍历完x的所有子节点之后才能找,因为这
//不是单独的一个环,试想所有环都套在一块那也是scc
//low[y]==dfn[x],必须是仍然在队里面
struct node
{
    int fr,to,nxt;
}e[N<<1];
int tot=1,head[N];
inline void add(int x,int y)
{
    e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot;
    e[tot].fr=x;
}
int dfn[N],dfn_cnt,low[N];
int stack[N],top;
bool in[N];
vector<int>scc[N];
int cnt;
inline void tarjan(int x)
{
    dfn[x]=low[x]=++dfn_cnt;
    stack[++top]=x;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(!dfn[to])
        {
            tarjan(to);
            low[x]=min(low[x],low[to]);
        }
        else if(in[to])low[x]=min(dfn[to],low[x]);
        
    }
    if(dfn[x]==low[x])
        {
            cnt++;
            int y;
            do
            {
                y=stack[top--];
                scc[cnt].push_back(y);ins[y]=0;c[y]=cnt;
            }while(y!=x)
        }
}
int main()
{
//    freopen("exam.txt","r",stdin);
//    freopen("a.out","w",stdout);
    n=re(),m=re();
    for(int i=1;i<=m;i++)
    {
        int x=re(),y=re();add(x,y);
    }
    _f(i,1,n)if(!dfn[i])tarjan(i);
    _f(i,2,tot)
    {
        if(c[e[i].fr]==c[e[i].to])continue;
        Add(e[i].fr,e[i].to);
    }
    return 0;
}

 



posted on 2022-07-05 16:40  HZOI-曹蓉  阅读(46)  评论(0编辑  收藏  举报