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);
}
