zoukankan      html  css  js  c++  java
  • tarjan算法(求强连通子块,缩点)

    tarjan算法求图中的强连通子图的个数。

     1 #include<iostream>
     2 
     3 #include<stack>
     4 #include<queue>
     5 #include<string>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<cmath>
     9 # define maxn 100005
    10 using namespace std;
    11 vector<int>wakaka[maxn];
    12 stack<int>q;
    13 int  low[maxn];
    14 int dfn[maxn];
    15 int vis[maxn];
    16 int num,ans;
    17 void tarjan(int u)//u始终代表父亲节点
    18 {
    19     low[u]=dfn[u]=++num;
    20     q.push(u);
    21     vis[u]=1;
    22     int len=wakaka[u].size();
    23     for(int i=0; i<len; i++)
    24     {
    25         int v=wakaka[u][i];
    26         if(vis[v]==0)
    27         {
    28             tarjan(v);
    29             low[u]=min(low[u],low[v]);
    30         }
    31         if(vis[v])
    32         {
    33             low[u]=min(low[u],dfn[v]);
    34         }
    35     }
    36     if(low[u]==dfn[u])
    37     {
    38         ans++;
    39         int top;
    40         do
    41         {
    42             top=q.top();
    43             q.pop();
    44             vis[top]=-1;
    45         }
    46         while(u!=top);
    47     }
    48 }
    49 int main()
    50 {
    51     int n,m;
    52     while(cin>>n>>m&&(n+m))
    53     {
    54         for(int i=1; i<=n; i++)
    55         {
    56             wakaka[i].clear();
    57         }
    58         ans=num=0;
    59         while(!q.empty())q.pop();
    60         memset(vis,0,sizeof(vis));
    61         for(int i=1; i<=m; i++)
    62         {
    63             int u,v;
    64             cin>>u>>v;
    65             wakaka[u].push_back(v);
    66         }
    67         for(int i=1; i<=n; i++)
    68         {
    69             if(vis[i]==0)
    70             {
    71                 if(ans>=2){
    72                   break;
    73                   }
    74                       tarjan(i);
    75             }
    76         }
    77         if(ans==1)
    78         cout<<"Yes"<<endl;
    79         else {
    80         cout<<"No"<<endl;
    81         }
    82         }
    83     return 0;
    84 }

     

    tarjan算法缩点运算的使用具体事例

    题目链接:http://poj.org/problem?id=2186

    具体大意:假设有三头公牛a,b,c。a仰慕b,b仰慕c,那么这个c就是剩下的所有公牛的仰慕对象,然后这个题就是让你算出符合条件的公牛一共有多少头。

    具体思路:首先,建成一个连通图,通过tarjan算法,然后对强连通子图进行缩点,对缩点后的“新”图来说,求出度为0的缩点中牛的数目。(这个题有一个坑点,就是条件是只要当前的这头牛被剩余的所有的牛仰慕就够了,它本身也可以再去崇拜别的牛,比如说 1  2 3构成一个强连通子图,输出结果应该是3,因为每一头牛都会被剩下的牛所仰慕。))

    代码如下:

      1 #include<iostream>
      2 #include<string>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<map>
      7 #include<vector>
      8 #include<stack>
      9 #include<queue>
     10 using namespace std;
     11 #define maxn 50005
     12 int low[maxn],dfn[maxn],vis[maxn],cnt[maxn],color[maxn],out[maxn];//low数组和dfn数组是tarjan算法的基本数组,vis数组是用来判断是否访问过的,cnt数组是用来存 染色后某一种具体颜色的点的个数,color数组是用来染色的,out数组是用来记录缩点之后,某一种颜色对应的出度
     13 int num,ans;
     14 vector<int>wakaka[maxn];
     15 stack<int>q;
     16 void tarjan(int u)
     17 {
     18     vis[u]=1;
     19     q.push(u);
     20     low[u]=dfn[u]=++num;
     21     int len=wakaka[u].size();
     22     for(int i=0; i<len; i++)
     23     {
     24         int v=wakaka[u][i];
     25         if(vis[v]==0)
     26         {
     27             tarjan(v);
     28             low[u]=min(low[u],low[v]);
     29         }
     30         if(vis[v]==1)
     31         {
     32             low[u]=min(low[u],dfn[v]);
     33         }
     34     }
     35     if(low[u]==dfn[u])
     36     {
     37         int top;
     38         ans++;
     39         do
     40         {
     41             top=q.top();
     42             q.pop();
     43             vis[top]=-1;
     44             color[top]=ans//对同一个连通图里的字块进行染色;
     45         }
     46         while(top!=u);
     47     }
     48 }
     49 
     50 int main()
     51 {
     52     int n,m;
     53     while(cin>>n>>m)
     54     {
     55         ans=num=0;
     56         while(!q.empty())q.pop();
     57         for(int i=1; i<=n; i++)
     58         {
     59             wakaka[i].clear();
     60         }
     61         memset(vis,0,sizeof(vis));
     62         memset(cnt,0,sizeof(cnt));
     63         memset(color,0,sizeof(color));
     64         memset(out,0,sizeof(out));
     65         for(int i=1; i<=m; i++)
     66         {
     67             int u,v;
     68             cin>>u>>v;
     69             wakaka[u].push_back(v);
     70         }
     71         for(int i=1; i<=n; i++)
     72         {
     73             if(vis[i]==0)
     74             {
     75                 tarjan(i);
     76             }
     77         }
     78         for(int i=1; i<=n; i++)
     79         {
     80         int t=color[i];
     81             int len=wakaka[i].size();
     82             for(int j=0; j<len; j++)
     83             {
     84            // cout<<i<<" "<<wakaka[i][j]<<endl;
     85                 if(t!=color[wakaka[i][j]])
     86                 {
     87                     out[t]++;//判断染色后某一个强连通子图的出度
     88                 }
     89             }
     90             cnt[t]++;//记录某一个颜色下自快的个数
     91         }
     92         //cout<<ans<<endl<<color[1]<<endl<<color[2]<<endl<<color[3]<<endl;
     93         int x=0,temp;
     94         for(int i=1; i<=ans; i++)
     95         {
     96        // cout<<i<<" "<<out[i]<<" "<<cnt[i]<<endl;
     97             if(out[i]==0)
     98             {
     99                 x++;
    100                 temp=cnt[i];
    101             }
    102             //cout<<temp<<endl;
    103         }
    104         if(x==1)//只能有一个出度为0的缩点,如果有两个的话是肯定不成立的,打个比方,牛角,两边的端点都是出度为0,但是两边不互相承认对方为最强。
    105         {
    106             cout<<temp<<endl;
    107         }
    108         else
    109         {
    110             cout<<0<<endl;
    111         }
    112     }
    113     return 0;
    114 }

     

     

     

  • 相关阅读:
    mysql数据库的相关练习题及答案
    数据库一
    python的协程
    jquery的常用知识点
    diehard–让你的程序更健壮
    迷宫塔生成工具
    编程解决谁是凶手的问题
    ClojureScript实现xpath定位器生成-1
    使用ClojureScript进行chrome扩展开发
    AES CBC模式下的Padding Oracle解密
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10263004.html
Copyright © 2011-2022 走看看