• hdu3594 强连通 tarjan


    题意: 判断是不是强连通图 ,同时每一条边必须只能在一个环里


    思路:之前我的强连通用的全是双深搜,结果题目的第二个要求很难判断,一开始写了三个深搜加上并查集,结果越写越乱,其实就是在判断一个边是否只在一个环内搞不定,后来看了下网上的代码,用的全是tarjan,没办法了,又学习了一下tarjan算法,学完后发现这个算法不错,比双深搜快一倍的时间吧,他的时间复杂度是O(n + m) n是点m是边,tarjan算法的运行步骤为第二问的解决提供了条件,其中的stack,low,dfn配合的很好,我们要开一个数组记录搜索路径,然后当我们搜到一个点发现他被搜过同时他还在stack中的话,我们直接通过路径数组原路返回到他,把路上所有的点的次数都加1(开个数组记录次数),如果发现有大于1的直接就NO了,还有就是点有一个点的次数不要加1,就是查找路径的第一个点的上一个点,也是路径中的最后一个点(因为是环),这样就ok了.


    #include<stdio.h>
    #include<string.h>
    #include<stack>
                                   
    #define N_node 25000 + 1000
    #define N_edge 55000 + 1000


    using namespace std;


    typedef struct
    {
       int to ,next;
    }STAR;


    STAR E[N_edge];
    int list[N_node] ,tot;
    int mer[N_node];
    int count[N_node];
    int DFN[N_node] ,LOW[N_node];
    int Index ,num ,okk;
    int instack[N_node];
    stack<int>st; 


    void add(int a ,int b)
    {
       E[++tot].to = b;
       E[tot].next = list[a];
       list[a] = tot;
    }


    int minn(int x ,int y)
    {
       return x < y ? x : y;
    }


    void merge(int e ,int s)
    {
       while(mer[s] != e)
       {
          count[s] ++;
          if(count[s] >= 2)
          {
             okk = 1;
             return ;
          }
          s = mer[s];
       }
    }


    void Tarjan(int s)
    {
       if(okk) return;
       DFN[s] = LOW[s] =  Index ++;
       st.push(s);
       instack[s] = 1;
       for(int k = list[s] ;k ;k = E[k].next)
       {
          int to = E[k].to;
          if(!DFN[to])
          {
             mer[to] = s;
             Tarjan(to);
             LOW[s] = minn(LOW[to] ,LOW[s]);
          }
          else if(instack[to])
          {
             LOW[s] = minn(DFN[to] ,LOW[s]);
             merge(to ,s);
             if(okk) return;       
          }
       }
       if(LOW[s] == DFN[s])
       {
          num ++;
          if(num > 1) okk = 1;   
          while(1)
          {
             int v = st.top();
             st.pop();
             instack[v] = 0;
             if(v == s) break;
          }
       }
       return ;
    }
     
    int main ()
    {
       int t ,i ,n ,a ,b;
       scanf("%d" ,&t);
       while(t--)
       {
          scanf("%d" ,&n);
          memset(list ,0 ,sizeof(list));
          memset(instack ,0 ,sizeof(instack));
          memset(DFN ,0 ,sizeof(DFN));
          memset(LOW ,0 ,sizeof(LOW));
          memset(count ,0 ,sizeof(count));
          for(i = 0 ;i < n ;i ++)mer[i] = i;
          while(!st.empty()) st.pop();
          tot = Index = 1 ,num = 0;
          while(scanf("%d %d" ,&a ,&b) && a + b)
          {
             add(a ,b);
          }
          okk = 0;
          for(i = 0 ;i < n ;i ++)
          {
             if(okk) break;
             if(DFN[i]) continue;
             Tarjan(i);
          }
          if(okk) printf("NO ");
          else printf("YES ");
       }
       return 0;
    }
          
             
             

  • 相关阅读:
    【足迹C++primer】46、动态存储类
    java foreach循环为什么不能赋值
    使用apktool解包和打包apk
    杭电 HDU ACM Milk
    [SQL基础]入门
    [c#基础]泛型集合的自定义类型排序
    [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!(续)
    [c#基础]使用抽象工厂实现三层
    [c#基础]DataTable的Select方法
    Winform模拟post请求和get请求登录网站
  • 原文地址:https://www.cnblogs.com/csnd/p/12063300.html
走看看 - 开发者的网上家园