• 图的Tarjan算法


    “Tarjan有三种算法 你们知道吗”——Tar乙己

    void tarjan(int x)
    {
        low[x]=dfn[x]=++ind;
        q[++top]=x;mark[x]=1;
        for(int i=last[x];i;i=e[i].next)
            if(!dfn[e[i].to])
            {
                tarjan(e[i].to);
                low[x]=min(low[x],low[e[i].to]);
            }
            else if(mark[e[i].to])
                low[x]=min(low[x],dfn[e[i].to]);
        if(low[x]==dfn[x])
        {
            int now=0;scc++;
            while(now!=x)
            {
                now=q[top--];mark[now]=0;
                bl[now]=scc;num[scc]++;
            }
        }
    }
    缩点
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<stack> 
    #include<vector> 
    using namespace std;
    const int maxn=50010;
    int first[maxn],to[maxn],next[maxn],cnt,from[maxn];
    void add(int u,int v)
    {
        from[++cnt]=u;
        to[cnt]=v;
        next[cnt]=first[u];
        first[u]=cnt;
    }
    int dfn[maxn],low[maxn],vis[maxn],ind,scc,now,st[maxn],top;
    int isc[maxn];
    vector<int> bl[maxn];
    int blc;
    int tag[maxn];
    void Tarjan_dfs(int x,int fa)
    {
        int son=0;
        low[x]=dfn[x]=++ind;
        for(int i=first[x];i;i=next[i])
        {
            int now=to[i];
            if(!dfn[now])
            {
                st[++top]=i;son++;
                Tarjan_dfs(now,x);
                low[x]=min(low[x],low[now]);
                if(low[now]>=dfn[x])
                {
                    isc[x]=1;
                    bl[++blc].clear();
                    while(1)
                    {
                        int num=st[top--];
                        if(tag[from[num]]!=blc)
                        {
                            bl[blc].push_back(from[num]);
                            tag[from[num]]=blc;
                        }
                        if(tag[to[num]]!=blc)
                        {
                            bl[blc].push_back(to[num]);
                            tag[to[num]]=blc;
                        }
                        if(to[num]==now && from[num]==x)break;
                    }
                }
            }
            else if(dfn[now]<dfn[x] && now!=fa)
            {
                st[++top]=i;
                low[x]=min(low[x],dfn[now]);
            }
        }
        if(fa==0 && son==1)isc[x]=0;
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)if(!dfn[i])Tarjan_dfs(i,-1);
        cout<<blc<<endl;
        return 0;
    }
    点双连通分量
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<stack> 
    #include<vector> 
    using namespace std;
    const int maxn=50010;
    int first[maxn],to[maxn],next[maxn],cnt,from[maxn];
    void add(int u,int v)
    {
        from[++cnt]=u;
        to[cnt]=v;
        next[cnt]=first[u];
        first[u]=cnt;
    }
    int dfn[maxn],low[maxn],vis[maxn],ind,scc,now,st[maxn],top;
    int isb[maxn];
    vector<int> bl[maxn];
    int blc;
    int tag[maxn];
    void Tarjan_dfs(int x,int fa)
    {
        dfn[x]=low[x]=++ind;
        for(int i=first[x];i;i=next[i])
        {
            int v=to[i];
            if(!dfn[v])
            {
                Tarjan_dfs(v,x);
                low[x]=min(low[x],low[v]);
                if(low[v]>dfn[x])
                    isb[i]=isb[i^1]=1;
            }
            else if(dfn[v]<dfn[x] && v!=fa)low[x]=min(low[x],dfn[v]);
        }
    }
    int vis[maxn];
    void dfs(int x)
    {
        vis[x]=1;
        tag[x]=blc;
        for(int i=first[x];i;i=next[i])
        {
            int v=to[i];
            if(isb[v])continue;
            if(!vis[i])dfs(v);
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)if(!dfn[i])Tarjan_dfs(i,-1);
        for(int i=1;i<=n;i++)if(!vis[i]){blc++;dfs(i);}
        cout<<blc<<endl;
        return 0;
    }
    边双连通分量
  • 相关阅读:
    ButterKnife的使用以及不能自动生成代码问题的解决
    Android事件传递机制
    Java中四种引用类型
    Swiper
    table合并单元格 colspan(跨列)和rowspan(跨行)
    常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全
    解决firefox、chrome不兼容cursor:hand 设置鼠标为手型的方法
    js 验证表单 js提交验证类
    怎么解决浏览器兼容性问题
    JavaScript作用域链
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7761631.html
Copyright © 2020-2023  润新知