• 强连通专题


    POJ 2762 Going from u to v or from v to u?

    题意:判断该图的任意两点是否可达

    分析:tarjan后进行缩点,缩点后再建图,判断该图是否为单链式图形(只有一个叶结点)
            判断能到达该点的节点个数是否等于bcnt

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<stack>
    using namespace std;
    const int MN=2011;
    vector<int>edge[MN];
    vector<int>SCC[MN];
    stack<int>s;
    
    int low[MN],dfn[MN];
    int instack[MN],stap[MN];
    int belong[MN];
    int num[MN];
    int ind[MN];
    int tp,p;
    int bcnt;
    
    void tarjan(int x)
    {
        low[x]=dfn[x]=++tp;
        stap[++p]=x;
        instack[x]=1;
        for(int i=0;i<edge[x].size();i++)
        {
            int v=edge[x][i];
            if(dfn[v]==-1)
            {
                tarjan(v);
                if(low[x]>low[v])
                   low[x]=low[v];
            }
            else if(instack[v] && dfn[v]<low[x])
                   low[x]=dfn[v];
        }
        if(low[x]==dfn[x])
        {
            int top;
            do
            {
                top=stap[p];
                belong[top]=bcnt;
                instack[top]=0;
                p--;
            }while(x!=top);
            bcnt++;
        }
    }
    
    void topsort()
    {
        memset(num,0,sizeof(num));
        int i,u,v;
        while(!s.empty())
            s.pop();
        for(int i=0;i<bcnt;i++)
            if(ind[i]==0)
            {
                s.push(i);
                num[i]++;
            }
        while(!s.empty())
        {
            u=s.top();
            s.pop();
            for(int i=0;i<SCC[u].size();i++)
            {
                v=SCC[u][i];
                if(--ind[v]==0)
                {
                    s.push(v);
                    num[v]=num[u]+1;
                }
            }
        }
    }
    
    int main()
    {
        int T,n,m,i,a,b,j;
        scanf("%d",&T);
        while(T--)
        {
            bcnt=tp=p=0;
            scanf("%d%d",&n,&m);
            memset(dfn,-1,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(instack,0,sizeof(instack));
            memset(belong,0,sizeof(belong));
            memset(ind,0,sizeof(ind));
            for(i=1;i<=n;i++)
            {
                edge[i].clear();
                SCC[i].clear();
            }
            for(i=0;i<m;i++)
            {
                scanf("%d%d",&a,&b);
                edge[a].push_back(b);
            }
            for(i=1;i<=n;i++)
            {
                if(dfn[i]==-1) tarjan(i);
            }
            for(i=1;i<=n;i++)
            {
                for(j=0;j<edge[i].size();j++)
                {
                    int x=belong[i];
                    int y=belong[edge[i][j]];
                    if(x!=y)
                    {
                         SCC[x].push_back(y);
                         ind[y]++;
                    }
                }
            }
            topsort();
            int ans=-1;
            for(i=0;i<bcnt;i++)
            {
                ans=max(ans,num[i]);
            }
           // printf("%d
    ",ans);
            if(bcnt==ans) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    View Code

    POJ 2553  Popular Cows

    题意:若牛A崇拜牛B,牛B崇拜牛C,则牛A崇拜牛C,问总共有多少只牛受到其他所有牛的崇拜

    分析:若有环存在,则该环里的所有牛都互相崇拜,则可将环看成是一个点,后再构图,若想存在某个
            点的牛收到其他所有牛的崇拜,则该图必定是单链式图形(只有一个叶结点)
            tarjan缩点反向建图,然后只有一个入度为0

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<stack>
    using namespace std;
    const int MN=11000;
    vector<int>SCC[MN];
    vector<int>edge[MN];
    stack<int>s;
    
    int low[MN],dfn[MN];
    int instack[MN],stap[MN];
    int belong[MN];
    int num[MN];
    int ind[MN];
    int sum[MN];
    int tp,p;
    int bcnt;
    int n,m;
    int cnt;
    int pos;
    
    void tarjan(int x)
    {
        low[x]=dfn[x]=++tp;
        stap[++p]=x;
        instack[x]=1;
        for(int i=0;i<edge[x].size();i++)
        {
            int v=edge[x][i];
            if(dfn[v]==-1)
            {
                tarjan(v);
                if(low[x]>low[v])
                   low[x]=low[v];
            }
            else if(instack[v] && dfn[v]<low[x])
                 low[x]=dfn[v];
        }
        if(low[x]==dfn[x])
        {
            int top;
            do
            {
                top=stap[p];
                belong[top]=bcnt;
                sum[bcnt]++;
                instack[top]=0;
                p--;
            }while(x!=top);
            bcnt++;
        }
    }
    
    void topsort()
    {
        int u,v;
        stack<int>s;
        memset(num,0,sizeof(num));
        for(int i=0;i<bcnt;i++)
        {
            if(ind[i]==0)
            {
                s.push(i);
                pos=i;
                cnt++;
            }
        }
    }
    
    int main()
    {
        int i,j;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(dfn,-1,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(instack,0,sizeof(instack));
            memset(belong,0,sizeof(belong));
            memset(ind,0,sizeof(ind));
            memset(sum,0,sizeof(sum));
            bcnt=tp=p=0;
            for(i=1;i<=n;i++)
            {
                edge[i].clear();
                SCC[i].clear();
            }
            for(i=0;i<m;i++)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                edge[a].push_back(b);
            }
            for(i=1;i<=n;i++)
            {
                if(dfn[i]==-1) tarjan(i);
            }
            for(i=1;i<=n;i++)
            {
                for(j=0;j<edge[i].size();j++)
                {
                    int x=belong[i];
                    int y=belong[edge[i][j]];
                    if(x!=y)
                    {
                        SCC[y].push_back(x);
                        ind[x]++;
                    }
                }
            }
            int ans=0;
            cnt=0;
            topsort();
            if(cnt==1) printf("%d
    ",sum[pos]);
            else printf("0
    ");
        }
        return 0;
    }
    View Code

     POJ 2553  The Bottom of a Graph

    题意:求出所有sink集合,sink集合的定义若v可达w,则w必定也可达v,求出所有的叶结点便可
             而头节点不可以的原因是若v属于V,w不属于V,而v可达w,但是w不可达v,所以不可以
             至于叶结点呢,v可达w,其中w必定都属于V集合

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int MN=5010;
    vector<int>SCC[MN];
    vector<int>edge[MN];
    
    int low[MN],dfn[MN];
    int instack[MN],stap[MN];
    int belong[MN];
    int num[MN];
    int ind[MN];
    int rem[MN];
    int tp,p;
    int bcnt;
    int n,m;
    int cas;
    
    void tarjan(int x)
    {
        low[x]=dfn[x]=++tp;
        stap[++p]=x;
        instack[x]=1;
        for(int i=0; i<edge[x].size(); i++)
        {
            int v=edge[x][i];
            if(dfn[v]==-1)
            {
                tarjan(v);
                if(low[x]>low[v])
                    low[x]=low[v];
            }
            else if(instack[v] && dfn[v]<low[x])
                low[x]=dfn[v];
        }
        if(low[x]==dfn[x])
        {
            int top;
            do
            {
                top=stap[p];
                belong[top]=bcnt;
                instack[top]=0;
                p--;
            }
            while(x!=top);
            bcnt++;
        }
    }
    
    void topsort()
    {
        for(int i=0; i<bcnt; i++)
        {
            if(ind[i]==0)
            {
                for(int j=1; j<=n; j++)
                {
                    if(belong[j]==i) rem[cas++]=j;
                }
            }
        }
    }
    
    bool cmp(int a,int b)
    {
        return a<b;
    }
    
    int main()
    {
        int i,w,v,j;
        while(scanf("%d",&n) && n)
        {
            scanf("%d",&m);
            tp=p=bcnt=cas=0;
            memset(dfn,-1,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(instack,0,sizeof(instack));
            memset(belong,0,sizeof(belong));
            memset(ind,0,sizeof(ind));
            for(i=0; i<=n; i++)
            {
                edge[i].clear();
                SCC[i].clear();
            }
            for(i=0; i<m; i++)
            {
                scanf("%d%d",&w,&v);
                edge[w].push_back(v);
            }
            for(i=1; i<=n; i++)
            {
                if(dfn[i]==-1) tarjan(i);
            }
            for(i=1; i<=n; i++)
            {
                for(j=0; j<edge[i].size(); j++)
                {
                    int x=belong[i];
                    int y=belong[edge[i][j]];
                    if(x!=y)
                    {
                        SCC[y].push_back(x);
                        ind[x]++;
                    }
                }
            }
            topsort();
            sort(rem,rem+cas,cmp);
            printf("%d",rem[0]);
            for(i=1; i<cas; i++)
            {
                printf(" %d",rem[i]);
            }
            printf("
    ");
    
        }
        return 0;
    }
    View Code

     POJ 1523 SPF

    题意: 找出割点,且将割点拿掉后,存在几个连通分量
    分析:   构建一棵dfs树,序列dfn[i]为深度优先数,表示dfs时访问i节点的序号,low[i]表示从i节点出发能访问到的最小的深度优先数。
                当且仅当节点u满足如下两个条件之一时,u为割点:
                1.u为dfs树的根,且u至少有两个子节点。
                2.u不是dfs树的根,至少存在一个节点v是u的子节点,且low[v]>=dfn[u]。
                若u为割点,记subnets[u]为u的子节点数,则去掉u后,图被分成subnets[u]+1个部分(每个子节点的部分和u的祖先的部分),若u为dfs树的根,则分                                      
                成subnets[u]个部分(根节点没有祖先)。 
           以上全部算法均在dfs过程中完成。

    割点模板

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int MN=1111;
    
    struct Edge
    {
        int to,next;
    } edge[MN<<2];
    int dfn[MN];
    int low[MN];
    int head[MN<<2];
    int subnet[MN];
    int E;
    int tp;
    int root;
    int vis[MN];
    
    void Init()
    {
        memset(dfn,-1,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(head,-1,sizeof(head));
        memset(subnet,0,sizeof(subnet));
        memset(vis,0,sizeof(vis));
        E=tp=0;
    }
    
    void Add(int a,int b)
    {
        edge[E].to=b;
        edge[E].next=head[a];
        head[a]=E++;
    }
    
    void tarjan(int u,int fa){  //割点模板
        int son=0;
        vis[u]=1;
        dfn[u]=low[u]=++tp;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(vis[v]==1 && v!=fa)
                low[u]=min(low[u],dfn[v]);
            if(!vis[v]){
                tarjan(v,u);
                son++;
                low[u]=min(low[u],low[v]);
                if((u==root && son>1) || (u!=root && dfn[u]<=low[v]))
                    subnet[u]++;   //cut[u] 表示u这个点割边数
            }
        }
        vis[u]=2;
    }
    
    int main()
    {
        int i,cas=1,n,a,b,nodes;
        while(scanf("%d",&n) && n)
        {
            nodes=n;
            Init();
            scanf("%d",&b);
            Add(n,b);
            Add(b,n);
            while(scanf("%d",&a) && a)
            {
                scanf("%d",&b);
                if(nodes<a) nodes=a;
                if(nodes<b) nodes=b;
                Add(a,b);
                Add(b,a);
            }
            for(i=1; i<=nodes; i++)
            {
                if(dfn[i]==-1)
                {root=i;
                    tarjan(i,-1);
                    
                }
            }
            int flag=0;
            printf("Network #%d
    ",cas++);
            for(i=1; i<=nodes; i++)
            {
                if(subnet[i]>=1)
                {
                    flag=1;
                    printf("  SPF node %d leaves %d subnets
    ",i,subnet[i]+1);
                }
            }
            if(flag==0) printf("  No SPF nodes
    ");
            puts("");
        }
        return 0;
    }
    View Code

     

     

  • 相关阅读:
    程序员需要的各种PDF格式电子书【附网盘免费下载资源地址】
    Web安全大揭秘
    tar 压缩解压命令详解
    django开发项目的部署nginx
    CentOS7安装mysql-python模块
    我的博客站点上线了
    2006
    centos7安装pip
    mysql删除匿名用户
    FilenameFilter 文件名过滤
  • 原文地址:https://www.cnblogs.com/zsboy/p/3189126.html
Copyright © 2020-2023  润新知