zoukankan      html  css  js  c++  java
  • hdu1269强连通模板

    题意当强连通分量为1的时候输出Yes否者输出No。

    学习了一下强连通分量的步骤,给出算法详解http://www.byvoid.com/zht/blog/scc-tarjan(注:不能用IE浏览)

    该题也可以用双向dfs求强连通分量,这里给出Tarjan算法的模板,更适合变形。

    也贴上双向dfs的代码吧。

    代码Tarjan(这是网上有注释的代码,讲得很细):

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    
    #define MAXN 10010
    #define MAXM 100010
    
    struct Edge
    {
          int v, next;  
    }edge[MAXM];    //边结点数组 
    
    int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXM];
    // first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组 
    // Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号 
    int instack[10010];  // instack[]为是否在栈中的标记数组 
    int n, m, cnt, scnt, top, tot;
    
    void init()
    {
        cnt = 0;
        scnt = top = tot = 0;    //初始化连通分量标号,次序计数器,栈顶指针为0 
        memset(first, -1, sizeof(first));
        memset(DFN, 0, sizeof(DFN));   //结点搜索的次序编号数组为0,同时可以当是否访问的数组使用 
    }
    
    void read_graph(int u, int v) //构建邻接表 
    {
         edge[tot].v = v;
         edge[tot].next = first[u];
         first[u] = tot++;
    }
    
    void Tarjan(int v)       //Tarjan算法求有向图的强连通分量 
    {
         int min, t;
         DFN[v] = Low[v] = ++tot;    //cnt为时间戳
         instack[v] = 1;    //标记在栈中 
         stack[top++] = v;      //入栈 
         for(int e = first[v]; e != -1; e = edge[e].next)
         {   //枚举v的每一条边 
               int j = edge[e].v;   //v所邻接的边 
               if(!DFN[j])
               {   //未被访问 
                   Tarjan(j);    //继续向下找 
                   if(Low[v] > Low[j]) Low[v] = Low[j];  // 更新结点v所能到达的最小次数层 
               }
               else if(instack[j] && DFN[j] < Low[v])
               {   //如果j结点在栈内, 
                   Low[v] = DFN[j];
               }
         }
         if(DFN[v] == Low[v])
         {     //如果节点v是强连通分量的根 
               scnt++;   //连通分量标号加1 
               do
               {
                   t = stack[--top];   //退栈 
                   instack[t] = 0;   //标记不在栈中 
                   Belong[t] = scnt;   //出栈结点t属于cnt标号的强连通分量 
               }while(t != v);  //直到将v从栈中退出 
         }
    }
    
    void solve()
    {
         for(int i = 1; i <= n; i++)   //枚举每个结点,搜索连通分量
            if(!DFN[i])  //未被访问 
               Tarjan(i);  //则找i结点的连通分量 
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m) && (n || m))
        {
            init();
            while(m--)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                read_graph(u, v);
            }
            solve();     //求强连通分量 
            if(scnt == 1) printf("Yes\n");  //只有一个强连通分量,说明此图各个结点都可达
            else printf("No\n");
        }
        return 0;
    }


     

    双向DFS:

    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=10010;
    const int M=100010;
    struct Edge
    {
        int v,next;
    }edge1[M],edge2[M];
    
    int vis1[N],vis2[N];
    int tot1,tot2;
    int first1[N],first2[N];
    int num[N];
    int cn,ans;
    int belong[N];
    int a,b,n,m,j;
    void init()
    {
        ans=0;tot1=tot2=0;cn=0;
        memset(first1,-1,sizeof(first1));
        memset(first2,-1,sizeof(first2));
        memset(vis1,0,sizeof(vis1));
        memset(vis2,0,sizeof(vis2));
    }
    void add_edge(int a,int b)
    {
        tot1++;
        edge1[tot1].v=b;
        edge1[tot1].next=first1[a];
        first1[a]=tot1;
        tot2++;
        edge2[tot2].v=a;
        edge2[tot2].next=first2[b];
        first2[b]=tot2;
    }
    void DFS_1(int v)
    {
        vis1[v]=1;
        for(int i=first1[v];i!=-1;i=edge1[i].next)
        {
            if(!vis1[edge1[i].v])
            DFS_1(edge1[i].v);
        }
        num[cn++]=v;
    }
    void DFS_2(int v)
    {
        vis2[v]=1;
        for(int i=first2[v];i!=-1;i=edge2[i].next)
        {
            if(!vis2[edge2[i].v])
            DFS_2(edge2[i].v);
        }
    }
    int main()
    {
        while(cin>>n>>m,n||m)
        {
            init();
            for(int i=0;i<m;i++)
            {
                cin>>a>>b;
                add_edge(a,b);
            }
            for(int i=1;i<=n;i++)
            {
                if(!vis1[i])
                {
                    DFS_1(i);
                }
            }
            for(int i=cn-1;i>=0;i--)
            {
                if(!vis2[num[i]])
                {
                    DFS_2(num[i]);
                    ans++;
                }
            }
            if(ans==1)
            cout<<"Yes"<<endl;
            else
            cout<<"No"<<endl;
    
        }
        return 0;
    }
    


     

  • 相关阅读:
    Effective C# 学习笔记(三十五) 了解PLINQ如何实现并行算法
    Effective C# 学习笔记(三十八)理解Dynamic的得与失
    转单例的分析
    获取系统当前音量 和 监听系统音量 ios
    (转) iphone开发资源汇总
    xcode show line numbers
    为了编程方便的效率宏定义的一些代码
    ios6下cocos2d & ipad 调用摄像头报错问题 (在竖屏情况下调用Camera 会导致转屏)
    转KVC
    不记住的
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134180.html
Copyright © 2011-2022 走看看