Tarjan算法

1、求有向图的强连通分量

如果有向图G中的任何两个顶点都相互可达,则G称为一个强连通图。非强连通图的极大强连通子图称为有向图的强连通分量。

 

Tarjan算法是根据图的深度优先搜索,定义DFN(u)为顶点u在DFS中的次序编号,Low(u)为u或u的子树能够追溯到的最早的栈中顶点的次序编号,则

Low(u)=min{DFN(u),Low(v) if(u,v)是树枝边,DFN(v) if(u,v)是后向边}

当DFN(u)=Low(u)时,以u为根的搜索子树上所有顶点都一个强连通分支。

#include <iostream>
#include <stdio.h>
#include <stack>
using namespace std;

struct Edge
{
	int adj_vertex;
	Edge* next;
};

struct Vertex
{
	int vertex;
	Edge* head;
};

struct Graph
{
	Vertex vertices[50];
	int vertex_num;
};

int Visited[50];
int inStack[50];
int DFN[50];
int Low[50];
int time=0;
stack<int> S;

void Create_Graph(Graph *g)
{
	cout <<"enter the number of vertices:";
	cin >>g->vertex_num;

	for(int i=1;i<=g->vertex_num;++i)
	{
		g->vertices[i].vertex=i;
		g->vertices[i].head=NULL;
	}

	for(int i=1;i<=g->vertex_num;++i)
	{
		cin.clear();
		cout <<"enter vertex "<<i<<"'s edges:";
		int vtx;
		Edge* temp;
		while(cin >>vtx)
		{
			temp=new Edge;
			temp->adj_vertex=vtx;
			temp->next=g->vertices[i].head;
			g->vertices[i].head=temp;
		}
	}
}

void Tarjan(int u,const Graph *g)
{
	++time;
	DFN[u]=Low[u]=time;
	Visited[u]=1;
	S.push(u);
	inStack[u]=1;
	for(Edge* temp=g->vertices[u].head;temp;temp=temp->next)
	{
		int v=temp->adj_vertex;
		if(Visited[v]==0)
		{
			Tarjan(v,g);
			if(Low[u]>Low[v])
				Low[u]=Low[v];
		}
		else if(inStack[v] && Low[u]>DFN[v])
			Low[u]=DFN[v];
	}

	if(DFN[u]==Low[u])
	{
		int vtx;
		cout <<"set is:";
		do 
		{
			vtx=S.top();
			S.pop();
			inStack[vtx]=0;
			cout <<vtx<<" ";
		} while (vtx!=u);
	}
}

int main()
{
	Graph* g=new Graph;
	Create_Graph(g);
	for(int i=1;i<=g->vertex_num;++i)
	{
		Visited[i]=0;
		inStack[i]=0;
		DFN[i]=0;
		Low[i]=0;
	}
	for(int i=1;i<=g->vertex_num;++i)
		if(Visited[i]==0)
			Tarjan(i,g);
}


2、求割点

割点:在图G中删除一个顶点u及其相关的边后,图G的连通分支数增加。

定义DFN(u)为顶点u在DFS中的次序编号,Low(u)为u或u的搜索树子树中能通过非父子边追溯到的次序编号最小的顶点。

Low(u)=min{DFS(u),Low(v) if(u,v)是树枝边,DFS(v) if(u,v)是后向边}

一个顶点u是割点,当且仅当满足(1)或(2)

(1)u为树根,且u有多于一个子树

(2)u不为树根,且满足存在(u,v)为树枝边,使得DFS(u)<=Low(v)

#include <iostream>
#include <stdio.h>
#include <stack>
using namespace std;

struct Edge
{
	int adj_vertex;
	Edge* next;
};

struct Vertex
{
	int vertex;
	Edge* head;
};

struct Graph
{
	Vertex vertices[50];
	int vertex_num;
};

int Visited[50];
int inStack[50];
int DFN[50];
int Low[50];
int time=0;
stack<int> S;

void Create_Graph(Graph *g)
{
	cout <<"enter the number of vertices:";
	cin >>g->vertex_num;

	for(int i=1;i<=g->vertex_num;++i)
	{
		g->vertices[i].vertex=i;
		g->vertices[i].head=NULL;
	}

	for(int i=1;i<=g->vertex_num;++i)
	{
		cin.clear();
		cout <<"enter vertex "<<i<<"'s edges:";
		int vtx;
		Edge* temp;
		while(cin >>vtx)
		{
			temp=new Edge;
			temp->adj_vertex=vtx;
			temp->next=g->vertices[i].head;
			g->vertices[i].head=temp;
		}
	}
}

void Tarjan(int u,const Graph *g)
{
	++time;
	DFN[u]=Low[u]=time;
	Visited[u]=1;
	
	for(Edge* temp=g->vertices[u].head;temp;temp=temp->next)
	{
		int v=temp->adj_vertex;
		if(Visited[v]==0)
		{
			Tarjan(v,g);
			if(Low[u]>Low[v])
				Low[u]=Low[v];
		}
		else if(Low[u]>DFN[v])
			Low[u]=DFN[v];
	}

	if(DFN[u]==1 && g->vertices[u].head && g->vertices[u].head->next)
		cout <<"cutting point is "<<u<<endl;
	else if(DFN[u]>1)
	{
		for(Edge* temp=g->vertices[u].head;temp;temp=temp->next)
		{
			int v=temp->adj_vertex;
			if(DFN[u]<=Low[v])
			{
				cout <<"cutting point is "<<u<<endl;
				break;
			}
		}
	}
}

int main()
{
	Graph* g=new Graph;
	Create_Graph(g);
	for(int i=1;i<=g->vertex_num;++i)
	{
		Visited[i]=0;
		inStack[i]=0;
		DFN[i]=0;
		Low[i]=0;
	}
	for(int i=1;i<=g->vertex_num;++i)
		if(Visited[i]==0)
			Tarjan(i,g);
}

 

参考:http://www.byvoid.com/blog/scc-tarjan/

posted @ 2012-06-08 11:32  Cavia  阅读(3879)  评论(0编辑  收藏  举报