强连通分量总结

本文介绍了两种求解强连通分量的算法:Korasaju算法和Tarjan算法。Korasaju算法依赖于原图和转置图的强连通分量性质,通过后序排序和反向遍历来找出强连通分量。Tarjan算法则通过深度优先搜索,找到节点间的低点连接。同时,文章还探讨了有向无环图的性质和构造边双连通图的方法。
摘要由CSDN通过智能技术生成

1.主要写两个算法

1.1强连通分量之Korasaju

这个算法主要依赖的是图G与图G的转置强连通分量是一样的。

具体证明先不考虑了(既是强连通分量,正向可以到达,反向一定也可以到达)。

实现过程

1.    dfs原图G,并且记录结束时间(后序)。后序越大,为相对的根节点。(先这样理解)

2.    给后序节点从大到小排序。

3.    依次取后序大的节点在G的转置图上进行dfs,跳过已标记的点。

每dfs一次,标记数+1

Hint:

说下遍历顺序的原因,G的转置图上,节点的相对关系变了,原图的相对根结点在新图上变成了相对子节点,由原图G可知,原图的相对根节点是一定可以搜到原图的相对子节点的。若是在G转置图上也能搜到(因为是反向),那么二者一定属于同一强连通分量。若两节点不属于同一强连通分量,则从当前的节点会搜到原图中的相对根节点却搜不回来。所以要从原图的相对根节点开始搜(即当前图的相对子节点)

4.    标记数即为强连通分量的个数,且标记数相同的为同一强连通分量。

模板:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>edge[10010];
vector<int>rever[10010];
struct Node
{
   int End,id;
}P[10010];//结束
int flag[10010];//着色
int vis[10010];//标记
int index,col;
int outdegree[10010];//出度
int indegree[10010];//出度
int num[10010];//压缩数量
bool cmp(Node a,Node b)
{
   return a.End>b.End;
}
void dfs(int u)//原图G
{
   index++;P[u].id=u;
   vis[u]=1;
   int l=edge[u].size();
   for(int i=0;i<l;i++)
   {
      int k=edge[u][i];
      if(!vis[k])
      {
         dfs(k);    
         index++;
      }
   }
   P[u].End=index;
 
}
void reverdfs(int u)//G的转置
{
   vis[u]=1;
   flag[u]=col;
   num[col]++;
   int l=rever[u].size();
   for(int i=0;i<l;i++)
   {
      int k=rever[u][i];
      if(!vis[k])
      {
         reverdfs(k);
      }
   }
}
void init(int n)
{
   for(int i=0;i<=n;i++)
   {
      edge[i].clear();
      rever[i].clear();
   }
   memset(vis,0,sizeof(vis));
   memset(flag,0,sizeof(flag));
   memset(num,0,sizeof(num));
   memset(outdegree,0,sizeof(outdegree));
   memset(indegree,0,sizeof(indegree));
   memset(P,0,sizeof(P));
}
int main()
{
   int n,m;
   while(scanf("%d%d",&n,&m)!=EOF)
   {
      init(n);
      while(m--)//输入边
      {
         int a,b;
         scanf("%d%d",&a,&b);
         edge[a].push_back(b);
         rever[b].push_back(a);
      }
      index=1,col=1;
      for(int i=1;i<=n;i++)//防止图不连通
      {
         if(!vis[i])dfs(i);
      }
      sort(P+1,P+n+1,cmp);//按结束时间降序排序
      memset(vis,0,sizeof(vis));
      for(int i=1;i<=n;i++)
      {
         if(!vis[P[i].id])
         {
            reverdfs(P[i].id);
            col++;
         }
      }
      for(int i=1;i<=n;i++)//缩图+统计出度入度
      {
         int l=edge[i].size();
         for(int j=0;j<l;j++)
         {
            int a=i,b=edge[i][j];
            if(flag[a]!=flag[b])
            {
                outdegree[flag[a]]++;
                indegree[flag[b]]++;
            }
         }
      }
 
      //………………
   }
   return 0;
}

这个算法还有一个作用,就是求点的拓扑排序。反向dfs染色情况形成一种拓扑排序。

再说下拓扑排序;

假设把所有的强连通分量都各自看成一个点,假设从r 到s,r的后序大于s,有两种情况,(1) r与s

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值