参考:http://blog.csdn.net/cxllyg/article/details/7610265
题目:求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通,描述算法。
分析:
1. 最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点,图不再连通,则此点是割点,反之不是割点(图的连通性一般通过深搜来判定,是否能一次搜索完 全部顶点);
2. 通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类割点的特性:
(1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为割点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林;
(2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为割点。因为删去v,则其子树和图的其它部分被分割开来。
仍然利用深搜算法,只不过在这里定义visited[v]表示为深度优先搜索遍历图时访问顶点v的次序号,定义low[v]=Min{visited[v],low[w],visited[k]},其中w是顶点v在深度优先生成树上的孩子节点;k是顶点v在深度优先生成树上由回边联结的祖先节点。
割点判定条件:如果对于某个顶点v,存在孩子节点w且low[w]>=visited[v],则该顶点v必为关节点。因为当w是v的孩子节点时,low[w]>=visited[v],表明w及其子孙均无指向v的祖先的回边,那么当删除顶点v后,v的孩子节点将于其他节点被分割开来,从来形成新的连通分量。
#include <iostream> #include <string> using namespace std; #define MAX_NUM 10 typedef struct EdgeNode { int adjvex; struct EdgeNode *next; }EdgeNode; typedef struct VertexNode { string data; EdgeNode *first; }VertexNode,List[MAX_NUM]; typedef struct Graph { List vertexnode; int num_vertex; int num_edge; }Graph; int count = 0; int visit[MAX_NUM]; int low[MAX_NUM]; int get_location(Graph g, string s) { for(int i=0;i<g.num_vertex;i++) { if(s == g.vertexnode[i].data) return i; } return -1; } void create_graph(Graph &g)//创建无向图 { int i,j,k; string s1,s2; cout<<"请输入节点和边的个数:"; cin>>g.num_vertex>>g.num_edge; cout<<"请输入节点:"; for(i=0;i<g.num_vertex;i++) { cin>>g.vertexnode[i].data; g.vertexnode[i].first=NULL; } cout<<"请输入边:"<<endl; for(k=0;k<g.num_edge;k++) { cin>>s1>>s2; i = get_location(g,s1); j = get_location(g,s2); EdgeNode *p = new EdgeNode(); p->adjvex = j; p->next = g.vertexnode[i].first; g.vertexnode[i].first = p; EdgeNode *q = new EdgeNode(); q->adjvex = i; q->next = g.vertexnode[j].first; g.vertexnode[j].first = q; } } void find_core(Graph g, int index) { int min,w; EdgeNode *p; min = visit[index] = ++count; bool flag = false; for(p=g.vertexnode[index].first;p;p=p->next) { w = p->adjvex; if(visit[w]==0) { find_core(g,w); if(low[w] < min) min = low[w]; else if(low[w] >= min) { if(flag == false)//防止重复打印 { cout<<g.vertexnode[index].data<<" "; flag = true; } } } else if(visit[w] < min) { min = visit[w]; } } low[index]=min; } void find(Graph g) { int i; for(i=0;i<MAX_NUM;i++) { visit[i]=0; low[i]=65536; } visit[0] = 1;//从v0出发 low[0] = 1; count=1; EdgeNode *p = g.vertexnode[0].first; int index = p->adjvex; find_core(g,index); if(count < g.num_vertex)//v0至少有两个子图 { cout<<g.vertexnode[0].data<<" ";//v0是一个割点 p = p->next; while(p)//遍历其它的子图 { index = p->adjvex; if(visit[index]==0) find_core(g,index); p = p->next; } } } int main() { Graph g; create_graph(g); cout<<"割点如下:"<<endl; find(g); cout<<endl; return 0; }