您的位置:首页 > 其它

强连通分量_Kosaraju算法

2012-01-26 23:42 295 查看
//将图G通过深度优先遍历,记录退出访问的序列(此序列为一逆拓扑序),并逐一入栈(拓扑序),将图G转置(即边的方向反转),对栈顶每个元素进行逐一深度遍历,遍历到的元素即为一个强连通分量;如果已经之前被遍历,则不再重复遍历。(这里使用邻接矩阵,可以使用十字链表来实现正逆矩阵)
#include <iostream>
  using namespace std;
  const int MAXN = 110;
  typedef int AdjTable[MAXN]; //邻接表类型
  int n;
  bool flag[MAXN]; //访问标志数组
  int belg[MAXN]; //存储强连通分量,其中belg[i]表示顶点i属于第belg[i]个强连通分量
  int numb[MAXN]; //结束时间标记,其中numb[i]表示离开时间为i的顶点
  AdjTable adj[MAXN], radj[MAXN]; //邻接表,逆邻接表
  //用于第一次深搜,求得numb[1..n]的值
  void VisitOne(int cur, int &sig)
  {
  flag[cur] = true;
  for ( int i=1; i<=adj[cur][0]; ++i )
  {
  if ( false==flag[adj[cur][i]] )
  {
  VisitOne(adj[cur][i],sig);
  }
  }
  numb[++sig] = cur;
  }
  //用于第二次深搜,求得belg[1..n]的值
  void VisitTwo(int cur, int sig)
  {
  flag[cur] = true;
  belg[cur] = sig;
  for ( int i=1; i<=radj[cur][0]; ++i )
  {
  if ( false==flag[radj[cur][i]] )
  {
  VisitTwo(radj[cur][i],sig);
  }
  }
  }
  //Kosaraju算法,返回为强连通分量个数
  int Kosaraju_StronglyConnectedComponent()
  {
  int i, sig;
  //第一次深搜
  memset(flag+1,0,sizeof(bool)*n);
  for ( sig=0,i=1; i<=n; ++i )
  {
  if ( false==flag[i] )
  {
  VisitOne(i,sig);
  }
  }
  //第二次深搜
  memset(flag+1,0,sizeof(bool)*n);
  for ( sig=0,i=n; i>0; --i )
  {
  if ( false==flag[numb[i]] )
  {
  VisitTwo(numb[i],++sig);
  }
  }
  return sig;
  }


//正确性证明,见网络
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: