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/

你可能感兴趣的:(tar)