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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM