如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。

Kosaraju算法

来自"NOCOW"

跳转到: 导航, 搜索

这个算法的较为普遍的版本是:

 1.对原图进行DFS并将出栈顺序进行逆序,得到的顺序就是拓扑顺序
 2.将原图每条边进行反向
 3.按照1中生成顺序再进行DFS染色染成同色的是一个强连通块
 合理性:如果是强连通子图,那么反向没有任何影响,依然是强连通子图。
        但如果是单向的边连通,反向后再按原序就无法访问了(因此反向处理是对非强连通块的过滤)

下面的算法并不一定是根据以上算法写的,在这里只是对求图的强连通分量算法做下介绍 --121.18.89.190 08:48 2008年10月17日 (CST)True1023

/*这是一个求图的强连通分量的算法。*/

这部分代码缺乏必要的注释,可能很难理解。如果你是作者并且可以添加一些适当的解释,或者你不是作者但是看懂了这些内容并可以描述出来,那么这样做。如果这些代码很难理解,你也可以适当的标准重写这部分内容。
#include <cstdio>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
#define NMAX 11000 
 
vector< vector< int > > path;
vector< vector< int > > npath;
int n,m, scc;
int order[NMAX], order_pos, id[NMAX], id_total[NMAX];
bool vis[NMAX];
int out_degre[NMAX];
 
void dfs(int pos)
{
	int i,j,l;
	vis[pos] = true;
	l = path[pos].size();
	for (i=0;i<l;i++) {
		j = path[pos][i];
		if (!vis[j]) {
			dfs(j);
		}
	}
	order[ order_pos ++ ] = pos;//make order
}
 
void ndfs(int pos)
{
	int i,j,l;
	vis[pos] = true;
	id[pos] = scc;
	l = npath[pos].size();
	for (i=0;i<l;i++) {
		j = npath[pos][i];
		if (!vis[j]) {
			ndfs(j);
		}
	}
}
 
void Kosaraju()
{
	int i,j,l;
	//dfs in original graph
	memset(vis, 0, sizeof(vis));
	for (i=1; i<=n ;i++) {
		if (!vis[i]) {
			dfs(i);
		}
	}
	//dfs in inverse graph
	memset(vis, 0, sizeof(vis));
	memset(id, 0, sizeof(id));
	scc = 1;
	for (i=order_pos-1; i>=0 ;i--) {
		if (!vis[ order[i] ]) {
			ndfs(order[i]);
			scc ++;
		}
	}
	//statist
	scc --;
	memset(id_total, 0, sizeof(id_total));
	for (i=1;i<=n;i++) {
		id_total[ id[i] ] ++;
	}
 
	memset(out_degre, 0, sizeof(out_degre));
	for (i=1;i<=n;i++) {
		l = path[i].size();
		int id1 = id[i];
		for (j=0;j<l;j++) {
			int id2 = id[ path[i][j] ];
			if (id1 != id2) {//id1 -> id2
				out_degre[id1] ++;
			}
		}
	}
	int ans_id,zero_degre = 0;
	for (i=1;i<=scc;i++) {
		if (out_degre[i] == 0) {
			zero_degre ++;
			ans_id = i;
		}
	}
 
	if (zero_degre > 1) {
		printf("0\n");
	}
	else {
		printf("%d\n",id_total[ ans_id ]);
	}
}
 
int main()
{
	int i,j;
	while (scanf("%d %d",&n,&m)==2) {
		path.resize(n+10);
		npath.resize(n+10);
		for (i=0;i<=n;i++) {
			path[i].clear();
			npath[i].clear();
		}
		order_pos = 0;
		//set graph
		for (i=0;i<m;i++) {
			int x,y;
			scanf("%d %d",&x,&y);
			path[x].push_back(y);
			npath[y].push_back(x);
		}
		Kosaraju();
	}
}
pascal版本
                         ——市守沐Samuel
{
  Kosaraju Algorithm
     By Samuel
    2009.11.04
}
program Kosaraju;
 
var
   link,link2:array[0..110,0..110]of longint;
   a:array[0..110]of longint;
   p:longint;
   rec:array[0..110]of boolean;
   col:array[0..110]of longint;
   color,n,i,j,x:longint;
 
function max(a,b:longint):longint;
begin
  if a>b then exit(a) else exit(b);
end;
procedure sou(x:longint);
var
   i:longint;
begin
  rec[x]:=true;
  for i:=1 to link[x,0] do
    if not rec[link[x,i]] then sou(link[x,i]);
  inc(p);
  a[p]:=x;
end;
 
procedure sou2(x:longint);
var
   i:longint;
begin
  col[x]:=color;
  for i:=1 to link2[x,0] do
    if col[link2[x,i]]=0 then sou2(link2[x,i]);
end;
 
BEGIN
  //assign(input,inf);reset(input);
  //assign(output,ouf);rewrite(output);
  readln(n);
  for i:=1 to n do
  begin
    read(x);
    while x<>0 do
    begin
      inc(link[i,0]);
      link[i,link[i,0]]:=x;
      inc(link2[x,0]);
      link2[x,link2[x,0]]:=i;  { 2.将原图每条边进行反向}
      read(x);
    end;
    readln;
  end;
  fillchar(rec,sizeof(rec),0);
  for i:=1 to n do             { 1.对原图进行DFS↓}
    if not rec[i] then sou(i);
  color:=0;
  for i:=p downto 1 do         {并将出栈顺序a[i]进行逆序,得到的顺序就是拓扑顺序}
    if col[a[i]]=0 then
    begin
      inc(color);
      sou2(a[i]);              {3.按照1中生成顺序再进行DFS染色染成同色的是一个强连通块}
    end;
  //close(input);close(output);
END.
个人工具