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